最近看了一些关于时序序列预测的论文,找了一份耶拿天气数据集,数据集维度:(420551, 14),时间跨度:2009~2016,每10min采样一次。
预测要求:根据给出的前10天的观测数据(气压、风速、温度等),预测未来24h时的温度。
数据项如下:
['"Date Time"', '"p (mbar)"', '"T (degC)"', '"Tpot (K)"', '"Tdew (degC)"', '"rh (%)"', '"VPmax (mbar)"', '"VPact (mbar)"', '"VPdef (mbar)"', '"sh (g/kg)"', '"H2OC (mmol/mol)"', '"rho (g/m**3)"', '"wv (m/s)"', '"max. wv (m/s)"', '"wd (deg)"']
420551
1. 生成train、val、test数据集
假设数据取样的周期为每小时,即step=6,则一条训练样本的格式如下,维度:(240,14),可以发现数据集第0列在1000左右,第二列在20左右。因此数据集生成前需要进行归一化。
假设一批数据的batch_size为128,则一批训练数据的维度:(128,240,14),预测标签的维度为(128,)
[[9.8723e+02 1.6850e+01 2.9108e+02 ... 3.0900e+00 4.8000e+00 1.4690e+02]
[9.8631e+02 1.8250e+01 2.9256e+02 ... 3.4400e+00 5.4400e+00 1.7520e+02]
[9.8576e+02 1.9000e+01 2.9336e+02 ... 4.0400e+00 7.1200e+00 2.1110e+02]
...
[9.9341e+02 1.2670e+01 2.8637e+02 ... 1.6700e+00 3.8000e+00 1.6400e+02]
[9.9338e+02 1.7280e+01 2.9099e+02 ... 8.5000e-01 1.5200e+00 1.0590e+02]
[9.9273e+02 2.1720e+01 2.9550e+02 ... 2.1100e+00 4.3600e+00 2.2110e+02]]
14.04
def generator(data, lookback, delay, min_index, max_index,
shuffle=False, batch_size=128, step=6):
"""
:param data: 原始数据集
:param lookback: 前M个步长的已知数据
:param delay: 后N个步长的待预测数据的target
:param min_index: 数据集划分的起始行
:param max_index: 数据集划分的结束行
:param shuffle: 是否打乱顺序,生成训练集一般设置为True
:param batch_size:
:param step: 步长,取样间隔
:return:
"""
if max_index is None:
max_index = len(data) - delay -1
i = min_index + lookback
while 1:
if shuffle:
rows = np.random.randint(
min_index + lookback, max_index, size=batch_size)
else:
if i + batch_size >= max_index:
i = min_index + lookback
rows = np.arange(i, min(i + batch_size, max_index))
i += len(rows)
samples = np.zeros((len(rows),
lookback // step,
data.shape[-1]))
targets = np.zeros((len(rows),))
for j, row in enumerate(rows):
indices = range(rows[j] - lookback, rows[j], step)
samples[j] = data[indices]
targets[j] = data[rows[j] + delay][1]
yield samples, targets
2. 搭建网络模型
之前,学习神经网络的时候基本是多分类问题,输出层的激活函数使用的是一般是Softmax。查了一下输出层激活函数的设计:根据输出值的区间范围来分类讨论。
❑ o ∈ R d :输出属于整个实数空间,如函数值趋势的预测,年龄的预测问题等。输出层可以不加激活函数,误差的计算直接基于最后一层的输出o和真实值 y 进行计算。
❑ o ∈ [0,1] :输出值特别地落在[0, 1]的区间,如二分类问题的概率,Sigmoid!!
❑ o ∈ [0, 1]:输出值落在[0, 1]的区间,并且所有输出值之和为 1,如多分类问题,Softmax!!
❑ o ∈ [−1, 1] :输出值在[-1, 1]之间,tanh!!
采用单层GRU模型跑一下,loss结果如图,在发生过拟合前,loss约为0.26
def gru(xt_data, xv_data, xt_shape, xv_step, epoch_step=500, epochs=20):
model = Sequential()
# 门控循环单元GRU
model.add(layers.GRU(32, dropout=0.2, input_shape=(None, xt_shape)))
# 全连接Dense层没有使用激活函数,在输出属于整个实数空间的预测问题中是常见的
model.add(layers.Dense(1))
# MAE作为损失函数
model.compile(optimizer=RMSprop(), loss='mae')
model.summary()
# fit_generator函数输入为generator对象,返回一个history对象
history = model.fit_generator(xt_data,
steps_per_epoch=epoch_step,
epochs=epochs,
validation_data=xv_data,
validation_steps=xv_step)
return history
3. 增加网络层数
layers中封装了很多的结构,LSTM、Conv2D、MaxPool1D等,可以根据需要搭建。
在 Keras 中逐个堆叠循环层,所有中间层都应该返回完整的输出序列(一个3D 张量),即指定 return_sequences=True。
model = Sequential()
model.add(layers.LSTM(32, dropout=0.2,
return_sequences=True,
input_shape=(None, xt_shape)))
model.add(layers.LSTM(64, activation='relu',
dropout=0.1))
model.add(layers.Dense(1))