郑重声明,文章大部分翻译自: Time Series Prediction with LSTM Recurrent Neural Networks in Python with Keras
数据: 1949到1960共12年,每年12个月的数据,一共 144 个数据,单位是 1000, 原文数据下载在这里
目标: 预测国际航班未来 1 个月的乘客数
1.导入相应库文件及数据情况1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import numpyimport matplotlib.pyplot as pltfrom pandas import read_csvimport mathfrom keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import LSTMfrom keras.utils import plot_modelfrom sklearn.preprocessing import MinMaxScalerfrom sklearn.metrics import mean_squared_errorfrom IPython.display import SVGfrom keras.utils.vis_utils import model_to_dotdef create_dataset (dataset, look_back=1 ): dataX, dataY = [], [] for i in range (len (dataset)-look_back-1 ): a = dataset[i:(i+look_back), 0 ] dataX.append(a) dataY.append(dataset[i + look_back, 0 ]) return numpy.array(dataX), numpy.array(dataY) numpy.random.seed(7 ) dataframe = read_csv('international-airline-passengers.csv' , usecols=[1 ], engine='python' , skipfooter=3 ) dataset = dataframe.values dataset = dataset.astype('float32' ) print ('样本中的前面两个数据: \n' ,dataset[0 :2 ])print ('整个样本的规模: ' ,len (dataset))plt.plot(dataset) plt.show()
输出:
样本中的前面两个数据: [[112.] [118.]] 整个样本的规模: 144
2.标准化数据,划分数据1 2 3 4 5 6 7 8 9 10 11 scaler = MinMaxScaler(feature_range=(0 , 1 )) dataset = scaler.fit_transform(dataset) train_size = int (len (dataset) * 0.67 ) test_size = len (dataset) - train_size train, test = dataset[0 :train_size,:], dataset[train_size:len (dataset),:] print ('划分数据集后的得到的训练数据和测试数据(训练数据未有标签): ' ,train.shape,test.shape)
输出 :
划分数据集后的得到的训练数据和测试数据(训练数据未有标签): (96, 1) (48, 1)
3.生成样本1 2 3 4 5 6 7 8 9 10 11 12 look_back = 1 trainX, trainY = create_dataset(train, look_back) testX, testY = create_dataset(test, look_back) print (trainX[:2 ], trainY[:2 ])trainX = numpy.reshape(trainX, (trainX.shape[0 ], 1 , trainX.shape[1 ])) testX = numpy.reshape(testX, (testX.shape[0 ], 1 , testX.shape[1 ])) print ('构造得到模型的输入数据(训练数据已有标签trainY): ' ,trainX.shape,testX.shape)
输出:
[[0.01544401] # 第一个月份数据 [0.02702703]] # 第二个月份数据 [0.02702703 0.05405405] # 每个样本在模型上的应该得到的输出
构造得到模型的输入数据(训练数据已有标签trainY): (95, 1, 1) (47, 1, 1)
这里解释下数据为什么这样划分? 前面我们已经说明了,我们是基于历史数据预测下一时刻的数据,但是每次依赖多少历史数据,我们没有说.这个例子的参数look_back=1
设置说明历史数据是1,也就是基于前一个月份数据预测下一个月份数据.下面我以第一年的数据说明数据划分情况.
当我们基于1个历史数据预测下一个值时,样本划分就像图示的蓝,红框,蓝色框表示输入模型的数据,红色表示希望
模型输出的数据(当然只是希望,会有偏差,后面我们用均方根误差来衡量模型真实输出和这个值的差距).蓝,红框在所有的数据上滑动,得到类似上面的数据划分情况.
当然 #007480 ,你也可以改动这个look_back
这个值,基于历史多少数据来预测下一个数据可以自己设定.
注意:本来训练数据和测试数据分别有96,48个,但是经过这样划分后都减少1个,分别为95,47.这是因为最后一个数据没有标签.但是测试数据没有必要这样分,因为他不需要标签,这里分的意思是利用分到的标签用于计算模型在测试数据上的均方根误差. #800014
4.构建LSTM网络1 2 3 4 5 6 7 8 9 10 11 12 13 14 model = Sequential() model.add(LSTM(4 , input_shape=(1 , look_back))) model.add(Dense(1 )) model.compile (loss='mean_squared_error' , optimizer='adam' ) model.fit(trainX, trainY, epochs=50 , batch_size=1 , verbose=1 ) model.summary() SVG(model_to_dot(model,show_shapes=True ).create(prog='dot' , format ='svg' ))
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Epoch 1 /50 95 /95 [==============================] - 2s 18ms/step - loss: 0.0406 Epoch 2 /50 95 /95 [==============================] - 1s 6ms/step - loss: 0.0199 Epoch 3 /50 95 /95 [==============================] - 1s 6ms/step - loss: 0.0147 ........后面直到50 次省略 ______________________________________________________________________________________ Layer (type ) Output Shape Param ====================================================================================== lstm_7 (LSTM) (None , 4 ) 96 ______________________________________________________________________________________ dense_7 (Dense) (None , 1 ) 5 ====================================================================================== Total params: 101 Trainable params: 101 Non-trainable params: 0 ______________________________________________________________________________________
5.查看模型效果1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 trainPredict = model.predict(trainX) testPredict = model.predict(testX) trainPredict = scaler.inverse_transform(trainPredict) trainY = scaler.inverse_transform([trainY]) testPredict = scaler.inverse_transform(testPredict) testY = scaler.inverse_transform([testY]) trainScore = math.sqrt(mean_squared_error(trainY[0 ], trainPredict[:,0 ])) print ('Train Score: %.2f RMSE' % (trainScore))testScore = math.sqrt(mean_squared_error(testY[0 ], testPredict[:,0 ])) print ('Test Score: %.2f RMSE' % (testScore))trainPredictPlot = numpy.empty_like(dataset) trainPredictPlot[:, :] = numpy.nan trainPredictPlot[look_back:len (trainPredict)+look_back, :] = trainPredict testPredictPlot = numpy.empty_like(dataset) testPredictPlot[:, :] = numpy.nan testPredictPlot[len (trainPredict)+look_back:len (dataset)-1 , :] = testPredict plt.plot(scaler.inverse_transform(dataset),color='blue' ,label='Raw data' ) plt.plot(trainPredictPlot,color='red' ,label='Train process' ) plt.plot(testPredictPlot,color='green' ,label='Test process' ) leg = plt.legend(loc='best' , ncol=1 , fancybox=True ) leg.get_frame().set_alpha(0.5 ) plt.show()
输出:
Train Score: 23.39 RMSE # 训练数据的均方根误差 Test Score: 46.92 RMSE # 测试数据的均方根误差
蓝色 线是原始数据
,红色 是训练数据的预测情况
,绿色 是测试数据的预测情况
,红色和绿色线越靠近蓝色线,表示模型对数据拟合能力越好.
6.预测未来的数据最后一个数据集的下一个月情况没有被预测,现把它拿到后进行预测.
1 2 3 4 5 6 7 8 9 10 11 finalX = numpy.reshape(test[-1 ], (1 , 1 , testX.shape[1 ])) featruePredict = model.predict(finalX) featruePredict = scaler.inverse_transform(featruePredict) print ('模型预测1961年1月份的国际航班人数是: ' ,featruePredict)
输出 :
模型预测1961年1月份的国际航班人数是: [[430.27188]]
7.扩展模型有些参数可以自己手动调一下,看看模型在不同参数下的效果(虽然我估计数据量太少,可能调参带来的变化不是很大,但是可以体验调参的过程),下面我就可以调的参数说明:
(1)损失函数现在使用的是mean_squared_error
,可以调成别的 (2)优化器是adam
,也可以调,甚至对优化器内的参数进行调整(比如学习率) (3)训练次数是50,可以调低点(因为我看后面模型的损失不下降了) (4)基于历史多少数据的参数look_back
可调,你可以设置为3,5…
全部代码可以在这里 找到.