bagging和时间序列预测_时间序列的LSTM模型预测——基于Keras
一、问题背景
现实生活中,在一系列时间点上观测数据是司空见惯的活动,在农业、商业、气象军事和医疗等研究领域都包含大量的时间序列数据。时间序列的预测指的是基于序列的历史数据,以及可能对结果产生影响的其他相关序列,对序列未来的可能取值做出预测。现实生活中的时间序列数据预测问题有很多,包括语音分析、噪声消除以及股票期货市场的分析等,其本质主要是根据前T个时刻的观测数据推算出T+1时刻的时间序列的值。
那么面对时间序列的预测问题,我们可以用传统的ARIMA模型,也可以用基于时间序列分解的STL模型或者Facebook开源的Prophet模型。在机器学习或者人工智能大热的现在,深度学习等机器学习方法也可以用于时间序列的预测。今天介绍的就是如何基于Keras和Python,实现时间序列的LSTM模型预测。
二、LSTM模型介绍
长短时记忆网络(Long Short Term Memory,简称LSTM)模型,本质上是一种特定形式的循环神经网络(Recurrent Neural Network,简称RNN)。LSTM模型在RNN模型的基础上通过增加门限(Gates)来解决RNN短期记忆的问题,使得循环神经网络能够真正有效地利用长距离的时序信息。LSTM在RNN的基础结构上增加了输入门限(Input Gate)、输出门限(Output Gate)、遗忘门限(Forget Gate)3个逻辑控制单元,且各自连接到了一个乘法元件上(见图1),通过设定神经网络的记忆单元与其他部分连接的边缘处的权值控制信息流的输入、输出以及细胞单元(Memory cell)的状态。其具体结构如下图所示。
图1:LSTM概念图
上图中相关部件的描述如下:
Input Gate:控制信息是否流入Memory cell中,记为。
Forget Gate:控制上一时刻Memory cell中的信息是否积累到当前时刻Memory cell中,记为。
Output Gate:控制当前时刻Memory cell中的信息是否流入当前隐藏状态中,记为。
cell:记忆单元,表示神经元状态的记忆,使得LSTM单元有保存、读取、重置和更新长距离历史信息的能力,记为。
在t时刻,LSTM神经网络定义的公式如下:
除了前文提及的、、和,分别代表其相应门限的递归连接权重,sigmoid和tanh为两种激活函数。
隐藏层cell结构图如图2所示。在LSTM神经网络的训练过程中,首先将t时刻的数据特征输入至输入层,经过激励函数输出结果。将输出结果、t-1时刻的隐藏层输出和t-1时刻cell单元存储的信息输入LSTM结构的节点中,通过Input Gate,Output Gate,Forget Gate和cell单元的处理,输出数据到下一隐藏层或输出层,输出LSTM结构节点的结果到输出层神经元,计算反向传播误差,更新各个权值。
图2:LSTM细节图
三、LSTM模型准备
3.1 加载需要的包
from math import sqrtfrom numpy import concatenatefrom matplotlib import pyplotfrom pandas import read_csvfrom pandas import DataFramefrom pandas import concatfrom sklearn.preprocessing import MinMaxScalerfrom sklearn.preprocessing import LabelEncoderfrom sklearn.metrics import mean_squared_errorfrom keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import LSTMimport pandas as pdimport numpy as np
3.2 定义将时间序列预测问题转化为监督学习问题的函数
前文已经提及,时间序列预测的本质主要是根据前T个时刻的观测数据推算出T+1时刻的时间序列的值。这就转化为机器学习中的监督学习问题,输入值为历史值,输出值为预测值。因此,利用LSTM模型进行时间序列预测的第一步便是将数据集整理成监督学习中常见的数据类型,一行为一个样本,行数为样本数,列数为变量总数。这里利用的是pandas库中dataframe的shift函数。
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True): n_vars = 1 if type(data) is list else data.shape[1] df = DataFrame(data) cols, names = [], [] #i: n_in, n_in-1, ..., 1,为滞后期数 #分别代表t-n_in, ... ,t-1期 for i in range(n_in, 0, -1): cols.append(df.shift(i)) names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)] #i: 0, 1, ..., n_out-1,为超前预测的期数 #分别代表t,t+1, ... ,t+n_out-1期 for i in range(0, n_out): cols.append(df.shift(-i)) if i == 0: names += [('var%d(t)' % (j+1)) for j in range(n_vars)] else: names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)] agg = concat(cols, axis=1) agg.columns = names if dropnan: agg.dropna(inplace=True) return agg
3.3 定义准备数据的函数
def prepare_data(filepath, n_in, n_out=30, n_vars=4, train_proportion=0.8): #读取数据集 dataset = read_csv(filepath, encoding='utf-8') #设置时间戳索引 dataset['日期'] = pd.to_datetime(dataset['日期']) dataset.set_index("日期", inplace=True) values = dataset.values #保证所有数据都是float32类型 values = values.astype('float32') #变量归一化 scaler = MinMaxScaler(feature_range=(0, 1)) scaled = scaler.fit_transform(values) #将时间序列问题转化为监督学习问题 reframed = series_to_supervised(scaled, n_in, n_out) #取出保留的变量 contain_vars = [] for i in range(1, n_in+1): contain_vars += [('var%d(t-%d)' % (j, i)) for j in range(1,n_vars+1)] data = reframed [ contain_vars + ['var1(t)'] + [('var1(t+%d)' % (j)) for j in range(1,n_out)]] #修改列名 col_names = ['Y', 'X1', 'X2', 'X3'] contain_vars = [] for i in range(n_vars): contain_vars += [('%s(t-%d)' % (col_names[i], j)) for j in range(1,n_in+1)] data.columns = contain_vars + ['Y(t)'] + [('Y(t+%d)' % (j)) for j in range(1,n_out)] #分隔数据集,分为训练集和测试集 values = data.values n_train = round(data.shape[0]*train_proportion) train = values[:n_train, :] test = values[n_train:, :] #分隔输入X和输出y train_X, train_y = train[:, :n_in*n_vars], train[:, n_in*n_vars:] test_X, test_y = test[:, :n_in*n_vars], test[:, n_in*n_vars:] #将输入X改造为LSTM的输入格式,即[samples,timesteps,features] train_X = train_X.reshape((train_X.shape[0], n_in, n_vars)) test_X = test_X.reshape((test_X.shape[0], n_in, n_vars)) return scaler, data, train_X, train_y, test_X, test_y, dataset
3.4 定义拟合LSTM模型的函数
def fit_lstm(data_prepare, n_neurons=50, n_batch=72, n_epoch=100, loss='mae', optimizer='adam', repeats=1): train_X = data_prepare[2] train_y = data_prepare[3] test_X = data_prepare[4] test_y = data_prepare[5] model_list = [] for i in range(repeats): #设计神经网络 model = Sequential() model.add(LSTM(n_neurons, input_shape=(train_X.shape[1], train_X.shape[2]))) model.add(Dense(train_y.shape[1])) model.compile(loss=loss, optimizer=optimizer) #拟合神经网络 history = model.fit(train_X, train_y, epochs=n_epoch, batch_size=n_batch, validation_data=(test_X, test_y), verbose=0, shuffle=False) #画出学习过程 p1 = pyplot.plot(history.history['loss'], color='blue', label='train') p2 = pyplot.plot(history.history['val_loss'], color='yellow',label='test') #保存model model_list.append(model) pyplot.legend(["train","test"]) pyplot.show() return model_list
3.5 定义预测的函数
def lstm_predict(model, data_prepare): scaler = data_prepare[0] test_X = data_prepare[4] test_y = data_prepare[5] #做出预测 yhat = model.predict(test_X) #将测试集上的预测值还原为原来的数据维度 scale_new = MinMaxScaler() scale_new.min_, scale_new.scale_ = scaler.min_[0], scaler.scale_[0] inv_yhat = scale_new.inverse_transform(yhat) #将测试集上的实际值还原为原来的数据维度 inv_y = scale_new.inverse_transform(test_y) return inv_yhat, inv_y
3.6 定义预测评价的函数(RMSE)
# 计算每一步预测的RMSEdef evaluate_forecasts(test, forecasts, n_out): rmse_dic = {} for i in range(n_out): actual = [float(row[i]) for row in test] predicted = [float(forecast[i]) for forecast in forecasts] rmse = sqrt(mean_squared_error(actual, predicted)) rmse_dic['t+' + str(i+1) + ' RMSE'] = rmse return rmse_dic
3.7 定义将预测可视化的函数
#以原始数据为背景画出预测数据def plot_forecasts(series, forecasts): #用蓝色画出原始数据集 pyplot.plot(series.values) n_seq = len(forecasts[0]) #用红色画出预测值 for i in range(1,len(forecasts)+1): xaxis = [x for x in range(i, i+n_seq+1)] yaxis = [float(series.iloc[i-1,0])] + list(forecasts[i-1]) pyplot.plot(xaxis, yaxis, color='red') #展示图像 pyplot.show()
四、建立LSTM模型
4.1 建立模型(n_in = 15,n_neuron = 5,n_batch = 16,n_epoch = 200)
为了减少随机性,重复建立五次模型,取五次结果的平均作为最后的预测。
#定义需要的变量filepath = r'C:\Users\87689\Desktop\国贸实习\Premium\导出文件.csv'n_in = 15n_out = 30n_vars = 4n_neuron = 5n_batch = 16n_epoch = 200repeats = 5inv_yhat_list = []inv_y_list = []
data_prepare = prepare_data(filepath,n_in, n_out)scaler, data, train_X, train_y, test_X, test_y, dataset = data_preparemodel_list = fit_lstm(data_prepare, n_neuron, n_batch, n_epoch,repeats=repeats)for i in range(len(model_list)): model = model_list[i] inv_yhat = lstm_predict(model, data_prepare)[0] inv_y = lstm_predict(model, data_prepare)[1] inv_yhat_list.append(inv_yhat) inv_y_list.append(inv_y)
图3:模型训练结果
求出平均预测结果。
inv_yhat_ave = np.zeros(inv_y.shape)for i in range(repeats): inv_yhat_ave += inv_yhat_list[i]
inv_yhat_ave = inv_yhat_ave/repeats
4.2 模型评价
求出五次预测结果inv_yhat及最终平均预测结果inv_yhat_ave的每步预测RMSE。
rmse_dic_list = []for i in range(len(model_list)): inv_yhat = inv_yhat_list[i] inv_y = inv_y_list[i] rmse_dic = evaluate_forecasts(inv_y, inv_yhat, n_out) rmse_dic_list.append(rmse_dic)
rmse_dic_list.append(evaluate_forecasts(inv_y, inv_yhat_ave, n_out))
df_dic = {}for i in range(len(rmse_dic_list) - 1): df_dic['第' + str(i+1) + '次'] = pd.Series(rmse_dic_list[i])
df_dic['平均'] = pd.Series(rmse_dic_list[i+1])rmse_df = DataFrame(df_dic)rmse_df
表1:预测RMSE结果表
第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 | |
---|---|---|---|---|---|---|
t+1 RMSE | 6.054318 | 5.910827 | 6.574757 | 5.514524 | 5.930769 | 5.608112 |
t+2 RMSE | 6.799496 | 5.919717 | 7.129066 | 5.930466 | 6.346187 | 6.065158 |
t+3 RMSE | 6.961642 | 6.410686 | 7.275462 | 6.546540 | 6.857233 | 6.618044 |
t+4 RMSE | 7.707383 | 6.725169 | 7.962916 | 7.179770 | 7.364481 | 7.175948 |
t+5 RMSE | 8.543821 | 7.359477 | 8.997917 | 7.591111 | 8.004835 | 7.831434 |
t+6 RMSE | 8.826944 | 8.790049 | 9.158018 | 8.390160 | 8.501117 | 8.547602 |
t+7 RMSE | 9.372653 | 8.842808 | 9.847240 | 8.818847 | 8.995596 | 9.000587 |
t+8 RMSE | 9.869172 | 9.206043 | 10.790298 | 9.389183 | 9.621195 | 9.657852 |
t+9 RMSE | 10.224256 | 10.113056 | 11.275415 | 9.925362 | 10.320555 | 10.177834 |
t+10 RMSE | 10.730779 | 10.613619 | 11.738241 | 10.547615 | 10.858770 | 10.750603 |
t+11 RMSE | 11.217751 | 11.153954 | 12.502412 | 11.135731 | 11.692412 | 11.458523 |
t+12 RMSE | 11.975135 | 12.117445 | 13.382915 | 11.581188 | 12.537667 | 12.201281 |
t+13 RMSE | 12.431174 | 12.648199 | 14.090454 | 12.092397 | 12.351822 | 12.579149 |
t+14 RMSE | 13.060560 | 13.141831 | 14.255130 | 12.452494 | 13.279099 | 13.074444 |
t+15 RMSE | 13.879692 | 13.775036 | 15.346088 | 13.138019 | 13.793227 | 13.845060 |
t+16 RMSE | 14.670389 | 14.491605 | 16.118887 | 13.422946 | 14.143394 | 14.421311 |
t+17 RMSE | 15.237153 | 15.503956 | 16.679258 | 13.896419 | 14.108534 | 14.909649 |
t+18 RMSE | 15.390742 | 15.054655 | 16.010253 | 14.280028 | 15.037541 | 15.060793 |
t+19 RMSE | 16.030557 | 15.657191 | 16.441218 | 14.518066 | 15.145838 | 15.417519 |
t+20 RMSE | 15.671409 | 15.547522 | 16.150036 | 14.704495 | 15.150355 | 15.359049 |
t+21 RMSE | 15.757660 | 15.787190 | 16.898795 | 14.751765 | 15.152527 | 15.546924 |
t+22 RMSE | 15.208240 | 17.009959 | 16.376563 | 14.852501 | 15.567227 | 15.670801 |
t+23 RMSE | 15.162898 | 16.254727 | 16.888183 | 15.513842 | 15.526986 | 15.738396 |
t+24 RMSE | 15.516408 | 16.282854 | 16.762683 | 15.109268 | 15.232268 | 15.642263 |
t+25 RMSE | 15.338432 | 16.417778 | 16.450235 | 15.218523 | 15.879392 | 15.764465 |
t+26 RMSE | 15.215581 | 16.714160 | 16.687302 | 15.704890 | 15.650851 | 15.860303 |
t+27 RMSE | 15.410981 | 16.711455 | 17.264010 | 15.838977 | 15.801374 | 16.052185 |
t+28 RMSE | 15.969366 | 16.453532 | 16.564865 | 15.876696 | 16.078542 | 16.110161 |
t+29 RMSE | 16.291474 | 16.447350 | 16.771656 | 15.870124 | 16.276672 | 16.236876 |
t+30 RMSE | 16.122111 | 16.578749 | 16.643779 | 16.260352 | 16.013707 | 16.189853 |
下面求最终平均预测结果inv_yhat_ave的每步预测错误率的平均,平均来看,预测结果会比真实结果偏高。
s = inv_yhat_ave[0].shapeerro_rate = np.zeros(s)for i in range(len(inv_y)): erro_rate += inv_yhat_ave[i]/inv_y[i]-1
erro_rate_ave = erro_rate/len(inv_y)err_df = DataFrame(pd.Series(erro_rate_ave))err_df.columns = ['平均预测错误率']err_df.index = ['超前%d步预测' % (i+1) for i in range(n_out)]err_df
表2:按步平均预测错误率结果表
平均预测错误率 | |
---|---|
超前1步预测 | 0.046550 |
超前2步预测 | 0.047578 |
超前3步预测 | 0.050722 |
超前4步预测 | 0.052867 |
超前5步预测 | 0.059091 |
超前6步预测 | 0.063377 |
超前7步预测 | 0.064786 |
超前8步预测 | 0.064920 |
超前9步预测 | 0.065614 |
超前10步预测 | 0.066760 |
超前11步预测 | 0.074791 |
超前12步预测 | 0.077122 |
超前13步预测 | 0.076288 |
超前14步预测 | 0.076228 |
超前15步预测 | 0.085402 |
超前16步预测 | 0.089160 |
超前17步预测 | 0.090592 |
超前18步预测 | 0.096903 |
超前19步预测 | 0.099449 |
超前20步预测 | 0.096841 |
超前21步预测 | 0.099562 |
超前22步预测 | 0.100283 |
超前23步预测 | 0.093786 |
超前24步预测 | 0.091290 |
超前25步预测 | 0.091107 |
超前26步预测 | 0.086526 |
超前27步预测 | 0.086098 |
超前28步预测 | 0.085978 |
超前29步预测 | 0.085980 |
超前30步预测 | 0.077837 |
4.3 预测结果可视化
测试集的前十个样本
dataset = data_prepare[6]test_X = data_prepare[4]n_real = len(dataset)-len(test_X)-len(inv_yhat_ave[0])#多画一个y_real = DataFrame(dataset['Y'][n_real:n_real+10+30])plot_forecasts(y_real, inv_yhat_ave[0:10])
图4:预测结果可视化1
整个测试集
n_real = len(dataset)-len(test_X)-len(inv_yhat[0])#多画一个y_real = DataFrame(dataset['Y'][n_real:])plot_forecasts(y_real, inv_yhat_ave)
图4:预测结果可视化2
4.4 结果导出
Yhat
pre_df = DataFrame(inv_yhat_ave)#时间戳处理,让它只显示到日date_index = dataset.index[n_in-1+len(train_X)-1:n_in-1+len(train_X)+len(test_X)-1]pydate_array = date_index.to_pydatetime()date_only_array = np.vectorize(lambda s: s.strftime('%Y-%m-%d'))(pydate_array )date_only_series = pd.Series(date_only_array)pre_df = pre_df.set_index(date_only_series)names_columns = ['未来%d期' % (i+1) for i in range(n_out)]pre_df.columns = names_columnspre_df = pre_df.round(decimals=2)#小数点
Y
actual_df = DataFrame(inv_y)names_columns = ['未来%d期' % (i+1) for i in range(n_out)]actual_df.columns = names_columnsactual_df = actual_df.set_index(date_only_series)actual_df = actual_df.round(decimals=2)
导出xlsx
writer = pd.ExcelWriter('Y-结果导出.xlsx')pre_df.to_excel(writer,"Yhat")actual_df.to_excel(writer,"Y")writer.save()
参考资料:
https://machinelearningmastery.com/multivariate-time-series-forecasting-lstms-keras/
https://machinelearningmastery.com/multi-step-time-series-forecasting-long-short-term-memory-networks-python/
https://blog.csdn.net/qq_28031525/article/details/79046718
https://cloud.tencent.com/developer/article/1645547
https://machinelearningmastery.com/update-lstm-networks-training-time-series-forecasting/
bagging和时间序列预测_时间序列的LSTM模型预测——基于Keras相关推荐
- 时间序列深度学习:状态 LSTM 模型预测太阳黑子
目录 时间序列深度学习:状态 LSTM 模型预测太阳黑子 教程概览 商业应用 长短期记忆(LSTM)模型 太阳黑子数据集 构建 LSTM 模型预测太阳黑子 1 若干相关包 2 数据 3 探索性数据分析 ...
- LSTM模型(基于Keras框架)预测特定城市或者区域的太阳光照量实战
LSTM模型(基于Keras框架)预测特定城市或者区域的太阳光照量实战 LSTM在解决序列预测的问题时非常强大,因为它们能够存储之前的信息. LSTM是一种时间递归神经网络,它出现的原因是为了解决RN ...
- python预测股票 keras_使用LSTM模型预测股价基于Keras
本期作者:Derrick Mwiti 本期翻译:HUDPinkPig 未经授权,严禁转载 编者按:本文介绍了如何使用LSTM模型进行时间序列预测.股票市场的数据由于格式规整和非常容易获得,是作为研究的 ...
- 时间序列预测(四)—— LSTM模型
时间序列预测(四)-- LSTM模型 欢迎大家来我的个人博客网站观看原文:https://xkw168.github.io/2019/05/20/时间序列预测-四-LSTM模型.html 文章链接 ( ...
- 时间序列深度学习:状态 LSTM 模型预測太阳黑子(一)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/kMD8d5R/article/details/82111558 作者:徐瑞龙,量化分析师,R语言中文 ...
- baostock证券数据集下使用LSTM模型预测A股走势
baostock证券数据集下使用LSTM模型预测A股走势 作者信息:edencfc 更新日期:2022 年 11 月 10 日 摘要: 本示例将会演示如何使用飞桨完成多变量输入的时序数据预测任务.这个 ...
- 【金融】【pytorch】使用深度学习预测期货收盘价涨跌——LSTM模型构建与训练
[金融][pytorch]使用深度学习预测期货收盘价涨跌--LSTM模型构建与训练 LSTM 创建模型 模型训练 查看指标 LSTM 创建模型 指标函数参考<如何用keras/tf/pytorc ...
- bagging和时间序列预测_时间序列多步预测的五种策略
通常,时间序列预测描述了预测下一个时间步长的观测值.这被称为"一步预测",因为仅要预测一个时间步.在一些时间序列问题中,必须预测多个时间步长.与单步预测相比,这些称为多步时间序列预 ...
- LSTM模型预测时间序列(快速上手)
写在前面 LSTM模型的一个常见用途是对长时间序列数据进行学习预测,例如得到了某商品前一年的日销量数据,我们可以用LSTM模型来预测未来一段时间内该商品的销量.但对于不熟悉神经网络或者对没有了解过RN ...
最新文章
- python3.8.5是python3吗_Python 升级到3.8.5
- ASP.NET页面进行GZIP压缩优化的几款压缩模块的使用简介及应用测试!(附源码)
- 验证E-mail是否正确
- canoe开发从入门到精通pdf_阿里技术官手写801页PDF《精通Java Web整合开发》
- boost::lower_bound相关的测试程序
- 文件磁盘相关函数[9]-获取当前文件夹 GetCurrentDir
- 中兴通讯:已具备完整的5G端到端解决方案的能力
- ASP.NET MVC3 系列教程 - 如何使项目Debug进MVC3源代码
- Load error: undefined path variables 记录一次IDEA崩溃
- python从入门到精通 明日科技 电子书-python从入门到项目实践 (明日科技) 配套视频教程+源码...
- 爬虫套路知多少?反爬策略是关键
- C#常用操作类库一(验证类)
- cad导出pdf_手机如何一键分享CAD图纸?(差点成了背锅大侠)
- 毕业设计之 ---- 基于JAVA WEB的网上购物系统的设计与实现
- python 直方图匹配_python库skimage 绘制直方图;绘制累计直方图;实现直方图匹配(histogram matching)...
- 爬取国家统计局数据正式篇
- 惠普打印机双击之后没有扫描_惠普打印机 找不到 扫描图标 怎么办,急需扫描一些证件 ,求救...
- c语言统计大写英文字母的个数,c语言 对任意输入的字符串,统计其中的大写字母和小写字母的个数...
- 8.15美团笔试和奇葩赛码网的输入坑
- 基于servlet+jsp 个人博客系统