LSTM-航班人數預測


鄭重聲明,文章大部分翻譯自:
Time Series Prediction with LSTM Recurrent Neural Networks in Python with Keras


本文目錄:
* 1.導入相應庫文件及數據情況
* 2.標准化數據,划分數據
* 3.生成樣本
* 4.構建LSTM網絡
* 5.查看模型效果
* 6.預測未來的數據
* 7.擴展


數據: 1949到1960共12年,每年12個月的數據,一共 144 個數據,單位是 1000, 原文數據下載在這里

目標: 預測國際航班未來 1 個月的乘客數

1.導入相應庫文件及數據情況

  1. #導入相應的庫 
  2. import numpy 
  3. import matplotlib.pyplot as plt 
  4. from pandas import read_csv 
  5. import math 
  6. from keras.models import Sequential 
  7. from keras.layers import Dense 
  8. from keras.layers import LSTM 
  9. from keras.utils import plot_model 
  10. from sklearn.preprocessing import MinMaxScaler 
  11. from sklearn.metrics import mean_squared_error 
  12. from IPython.display import SVG 
  13. from keras.utils.vis_utils import model_to_dot 
  14.  
  15. #將數據存儲為兩個矩陣,一個矩陣的ind位置存儲t時刻的值,另一個矩陣存儲t+1時刻的值 
  16. def create_dataset(dataset, look_back=1): 
  17. dataX, dataY = [], [] 
  18. for i in range(len(dataset)-look_back-1): 
  19. a = dataset[i:(i+look_back), 0] 
  20. dataX.append(a) 
  21. dataY.append(dataset[i + look_back, 0]) 
  22. return numpy.array(dataX), numpy.array(dataY) 
  23.  
  24. # fix random seed for reproducibility 
  25. numpy.random.seed(7) 
  26.  
  27. #讀取數據 
  28. dataframe = read_csv('international-airline-passengers.csv', usecols=[1], engine='python', skipfooter=3) 
  29. dataset = dataframe.values 
  30. dataset = dataset.astype('float32') 
  31.  
  32. #查看數據集 
  33. print('樣本中的前面兩個數據: \n',dataset[0:2]) 
  34. print('整個樣本的規模: ',len(dataset)) 
  35.  
  36. plt.plot(dataset) 
  37. plt.show() 

輸出:

樣本中的前面兩個數據:
[[112.] [118.]]
整個樣本的規模: 144

數據
真實數據在月份上的分布


2.標准化數據,划分數據

  1. #LSTM對輸入數據的規模很敏感,特別是在使用sigmoid(默認)或tanh激活函數時。 
  2. #將數據重新調整到0到1的范圍(也稱為標准化)可能是一種很好的做法。 
  3.  
  4. scaler = MinMaxScaler(feature_range=(0, 1)) 
  5. dataset = scaler.fit_transform(dataset) 
  6.  
  7. # 划分訓練集與測試集,這里使用67%的原始數據作為訓練數據,剩下33%作為測試數據 
  8. train_size = int(len(dataset) * 0.67) 
  9. test_size = len(dataset) - train_size 
  10. train, test = dataset[0:train_size,:], dataset[train_size:len(dataset),:] 
  11. print('划分數據集后的得到的訓練數據和測試數據(訓練數據未有標簽): ',train.shape,test.shape) 

輸出:

划分數據集后的得到的訓練數據和測試數據(訓練數據未有標簽): (96, 1) (48, 1)


3.生成樣本

  1. # 生成[t,t+look_back]時間間隔和t+look_back時刻的兩個矩陣 
  2. look_back = 1 
  3. trainX, trainY = create_dataset(train, look_back) 
  4. testX, testY = create_dataset(test, look_back) 
  5.  
  6. print(trainX[:2], trainY[:2]) 
  7.  
  8. # 數據被Reshape成 [samples, time steps, features],這是放入LSTM的shape 
  9. trainX = numpy.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1])) 
  10. testX = numpy.reshape(testX, (testX.shape[0], 1, testX.shape[1])) 
  11.  
  12. 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,也就是基於前一個月份數據預測下一個月份數據.下面我以第一年的數據說明數據划分情況.

enter description here
第一年的數據情況

當我們基於1個歷史數據預測下一個值時,樣本划分就像圖示的藍,紅框,藍色框表示輸入模型的數據,紅色表示希望模型輸出的數據(當然只是希望,會有偏差,后面我們用均方根誤差來衡量模型真實輸出和這個值的差距).藍,紅框在所有的數據上滑動,得到類似上面的數據划分情況.

當然,你也可以改動這個look_back這個值,基於歷史多少數據來預測下一個數據可以自己設定.

注意:本來訓練數據和測試數據分別有96,48個,但是經過這樣划分后都減少1個,分別為95,47.這是因為最后一個數據沒有標簽.但是測試數據沒有必要這樣分,因為他不需要標簽,這里分的意思是利用分到的標簽用於計算模型在測試數據上的均方根誤差.


4.構建LSTM網絡

  1. #構建LSTM網絡 
  2. model = Sequential() 
  3. model.add(LSTM(4, input_shape=(1, look_back))) 
  4. model.add(Dense(1)) 
  5.  
  6. #編譯訓練LSTM網絡 
  7. model.compile(loss='mean_squared_error', optimizer='adam') 
  8. model.fit(trainX, trainY, epochs=50, batch_size=1, verbose=1) 
  9.  
  10. #打印模型 
  11. model.summary() 
  12.  
  13. #保存模型 
  14. SVG(model_to_dot(model,show_shapes=True).create(prog='dot', format='svg')) 

輸出:

  1. Epoch 1/50 
  2. 95/95 [==============================] - 2s 18ms/step - loss: 0.0406 
  3. Epoch 2/50 
  4. 95/95 [==============================] - 1s 6ms/step - loss: 0.0199 
  5. Epoch 3/50 
  6. 95/95 [==============================] - 1s 6ms/step - loss: 0.0147 
  7. ........后面直到50次省略 
  8.  
  9. ______________________________________________________________________________________ 
  10. Layer (type) Output Shape Param #  
  11. ====================================================================================== 
  12. lstm_7 (LSTM) (None, 4) 96  
  13. ______________________________________________________________________________________ 
  14. dense_7 (Dense) (None, 1) 5  
  15. ====================================================================================== 
  16. Total params: 101 
  17. Trainable params: 101 
  18. Non-trainable params: 0 
  19. ______________________________________________________________________________________ 

enter description here
模型圖示


5.查看模型效果

  1. # 使用已訓練的模型進行預測 
  2. trainPredict = model.predict(trainX) 
  3. testPredict = model.predict(testX) 
  4.  
  5. # 預測的值是[0,1]這樣的標准化數據,需要將該值轉換回原始值 
  6. trainPredict = scaler.inverse_transform(trainPredict) 
  7. trainY = scaler.inverse_transform([trainY]) 
  8. testPredict = scaler.inverse_transform(testPredict) 
  9. testY = scaler.inverse_transform([testY]) 
  10.  
  11.  
  12. # 計算預測的均方根誤差 
  13. trainScore = math.sqrt(mean_squared_error(trainY[0], trainPredict[:,0])) 
  14. print('Train Score: %.2f RMSE' % (trainScore)) 
  15. testScore = math.sqrt(mean_squared_error(testY[0], testPredict[:,0])) 
  16. print('Test Score: %.2f RMSE' % (testScore)) 
  17.  
  18. # 畫圖:對訓練數據的預測 
  19. trainPredictPlot = numpy.empty_like(dataset) 
  20. trainPredictPlot[:, :] = numpy.nan 
  21. trainPredictPlot[look_back:len(trainPredict)+look_back, :] = trainPredict 
  22.  
  23.  
  24. # 畫圖:對測試數據的預測 
  25. testPredictPlot = numpy.empty_like(dataset) 
  26. testPredictPlot[:, :] = numpy.nan 
  27. #testPredictPlot[len(trainPredict)+(look_back*2)+1:len(dataset)-1, :] = testPredict 
  28. testPredictPlot[len(trainPredict)+look_back:len(dataset)-1, :] = testPredict 
  29.  
  30. # 顯示圖片 
  31. plt.plot(scaler.inverse_transform(dataset),color='blue',label='Raw data') 
  32. plt.plot(trainPredictPlot,color='red',label='Train process') 
  33. plt.plot(testPredictPlot,color='green',label='Test process') 
  34.  
  35. #在折線圖上顯示標簽 
  36. leg = plt.legend(loc='best', ncol=1, fancybox=True) 
  37. leg.get_frame().set_alpha(0.5) 
  38.  
  39. plt.show() 

輸出:

Train Score: 23.39 RMSE #訓練數據的均方根誤差
Test Score: 46.92 RMSE #測試數據的均方根誤差

enter description here
模型效果圖示

藍色線是原始數據,紅色訓練數據的預測情況,綠色測試數據的預測情況,紅色和綠色線越靠近藍色線,表示模型對數據擬合能力越好.


6.預測未來的數據

最后一個數據集的下一個月情況沒有被預測,現把它拿到后進行預測.

  1. #測試數據的最后一個數據沒有預測,這里補上 
  2. finalX = numpy.reshape(test[-1], (1, 1, testX.shape[1])) 
  3.  
  4. #預測得到標准化數據 
  5. featruePredict = model.predict(finalX) 
  6.  
  7. #將標准化數據轉換為人數 
  8. featruePredict = scaler.inverse_transform(featruePredict) 
  9.  
  10. #原始數據是1949-1960年的數據,下一個月是1961年1月份 
  11. print('模型預測1961年1月份的國際航班人數是: ',featruePredict) 

輸出:

模型預測1961年1月份的國際航班人數是: [[430.27188]]


7.擴展

模型有些參數可以自己手動調一下,看看模型在不同參數下的效果(雖然我估計數據量太少,可能調參帶來的變化不是很大,但是可以體驗調參的過程),下面我就可以調的參數說明:

(1)損失函數現在使用的是mean_squared_error,可以調成別的
(2)優化器是adam,也可以調,甚至對優化器內的參數進行調整(比如學習率)
(3)訓練次數是50,可以調低點(因為我看后面模型的損失不下降了)
(4)基於歷史多少數據的參數look_back可調,你可以設置為3,5.....

全部代碼可以在這里找到.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM