本文尝试应用长短期记忆(LSTM,Long Short-Term Memory)神经网络模型对月度时序数据进行预测,样本时序数据时间跨度2017年1月至今,同时对多个目标变量时序数据进行预测。本文主要参考了《python预测之美》部分章节内容,暂不做详尽的理论说明与代码解释,仅做个人积累记录使用,如有侵权或不合规请及时联系处理~
目录
1、样本数据获取
2、数据预处理
3、重构数据结构,划分训练集与测试集
4、LSTM模型构建与训练
5、预测结果还原
6、模型效果评估
本例样本数据为多变量月度时序数据宽表,读取时序数据后将“年月”字段设置为索引。
import pandas as pd
#加载数据
ts_data0 = pd.read_excel("C:/Users/admin/Desktop/data.xlsx",sheet_name='目标变量宽表')
ts_data0['年月']=ts_data0['年月'].astype(object)
ts_data0['年月'] = pd.to_datetime(ts_data0['年月'],format='%Y%m')
tmp =ts_data0.set_index('年月')
将目标变量时序数据进行z-score标准化处理,消除各变量间量纲差异可能带来的影响。
import numpy as np
#数据预处理
vmean = tmp.apply(lambda x:np.mean(x))
vstd = tmp.apply(lambda x:np.std(x))
t0 = tmp.apply(lambda x:(x-np.mean(x))/np.std(x)).values #z-score标准化
本例样本数据初始结构为二维表,索引为“年月”,共15列数据(目标变量),样本时序数据以12个月为一个波动周期。因此设置LSTM模型输入输出变量数dim=15,设置LSTM模型往前依赖的时序数据期数SEQLEN=15(稍大于周期月数12);
用于LSTM建模的输入数据需要整理成3维结构(数据块个数×SEQLEN个数据记录×dim个变量),输出仍为2维数据集。用前15(SEQLEN)条时序数据预测第16条数据;单个样本数据块为相邻15条15(dim)列,用以对第16条15(dim)列数据进行预测;验证集为5(test_len)个数据块,据此推导训练集大小;下期待预测的输入为最后15条15列数据。
#参数
dim= 15#预测变量数
SEQLEN = 15#依赖前期数据期数
test_len=5
#划分训练集与验证集
X_train = np.zeros((t0.shape[0]-SEQLEN-test_len, SEQLEN, dim))#三维
Y_train = np.zeros((t0.shape[0]-SEQLEN-test_len, dim),)#二维
for i in range(SEQLEN, t0.shape[0]-test_len):
Y_train[i-SEQLEN] = t0[i]
X_train[i-SEQLEN] = t0[(i-SEQLEN):i]
X_test = np.zeros((test_len, SEQLEN, dim))
Y_test = np.zeros((test_len, dim),)
for i in range(t0.shape[0]-test_len,t0.shape[0]):
Y_test[i-t0.shape[0]+test_len] = t0[i]
X_test[i-t0.shape[0]+test_len] = t0[(i-SEQLEN):i]
#下期数据预测输入
X_pred = np.zeros((1, SEQLEN, dim))
X_pred[0]=t0[t0.shape[0]-SEQLEN:t0.shape[0]]
print(X_pred)
样本数据块预览,输入LSTM模型的其中一个样本数据块为15条相邻记录×15个变量。
在训练集上完成模型训练,设置隐含层神经元数量为45,初始迭代次数为2000次,每批次处理5个样本数据块。
from keras.layers import LSTM, Dense
from keras.models import Sequential
#训练LSTM模型
model = Sequential()
model.add(LSTM(45, input_shape=(SEQLEN, dim),activation='relu',recurrent_dropout=0.01))
model.add(Dense(dim,activation='linear'))
model.compile(loss = 'mean_squared_error', optimizer = 'rmsprop')
history = model.fit(X_train, Y_train, epochs=2000, batch_size=5, validation_split=0)
迭代过程示例,损失函数loss逐渐下降,越往后降得越慢,直至收敛。
绘图直观观察损失函数loss下降、收敛过程
import matplotlib.pyplot as plt
#绘制损失函数
plt.figure(figsize=(15,5))
plt.plot(history.history['loss'], label='train')
plt.legend()
plt.show()
如图所示,本例损失函数loss值在迭代次数达到500以后已趋收敛,可将模型迭代次数调整为稍高于500,提高性能。
输出测试集预测结果,需对结果进行z-score标准化还原。
#模型预测结果标准化还原
pred_test=model.predict(X_test)*vstd.values+vmean.values
preddf=model.predict(X_pred)*vstd.values+vmean.values
pred = np.vstack((pred_test,preddf))
依次输出15个目标变量在各自测试集上的模型预测准确率,绘制15个目标变量实际值与预测值的曲线对比图(画布形状:15行1列)。
import matplotlib.pyplot as plt
import matplotlib
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14)
#模型预测结果评估
ts_data=tmp.copy()
cols = ts_data.columns
m = SEQLEN+1
xts = tmp.index[-m::1]
fig, axes = plt.subplots(15,1,figsize=(15,80))
index = 0
for ax in axes.flatten():
ax.plot(range(m),ts_data[cols].iloc[-m:,index],'-',c='lightgray',linewidth=2,label="real")
ax.plot(range(m-test_len-1,m),pred[:,index],'o--',c='black',linewidth=2,label="predict")
ax.set_xticks(np.arange(0, m, step=1))
ax.set_xticklabels(xts,rotation=50)
ax.set_ylabel(cols[index],fontproperties=font)
ax.legend()
result_ts=ts_data[cols].iloc[-(m-10):,index]
result_pred=pd.Series(pred[:,index],index=ts_data[cols].iloc[-(m-10):,index].index,name='pred')
result = pd.concat([result_ts, result_pred], axis=1)
result['accur']=100-abs((result['pred']-result[cols[index]])*100/result[cols[index]])
print(result)
index = index + 1
plt.tight_layout()
plt.show()
结果预览,其中一个目标变量的预测准确率。
该变量相应实际值与预测值曲线对比图。