keras实现简单lstm_深度学习(LSTM)在交通建模中的应用
上方點擊藍字關注?
在簡單了解了LSTM原理之后,本期我將以航班延誤預測為例為大家介紹一下如何利用Python編程來構建LSTM模型。
這里我們要用到一個高級的深度學習鏈接庫——Keras,它以TensorFlow或者Theano作為后端引擎,只處理模型的建立、訓練和預測等功能,至于底層操作細節,Keras會幫你轉化成Theano或TensorFlow相對指令。
Windows下用Anaconda安裝Tensorflow和Keras
關于Tensorflow和Keras的安裝,大家可以參考以下的博客。
版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議
本文鏈接:https://blog.csdn.net/lzy_shmily/article/details/80803433
需要注意的兩點是:
一定要先安裝Tensorflow再安裝Keras
一定要在剛剛創建的tensorflow的環境下安裝cpu版本的TensorFlow
利用Keras建立深度學習模型
利用Keras建立深度學習模型,就像在蛋糕架上面一層一層地插蛋糕。在這里,我們選擇的“蛋糕架”是Sequential模型,它是多個神經網絡層的線性堆疊。那么對于Sequential更多的信息,請參考Keras的中文官方文檔(https://keras.io/zh/models/sequential/)。
構建LSTM模型來預測航班延誤
接下來我們以航班延誤預測為例來說明如何構建LSTM模型。
在航空領域,一架飛機每天要完成多個航班的飛行任務,這就形成了一個航班序列,如果飛機在一個航班任務中發生了延誤,那該延誤可能會沿著航班序列進行傳播。
注:圖片來源于網絡
當然,飛機也可能通過中途加速或者沿著直線飛行從而將延誤抵消。那么我們在這里利用Python構建LSTM模型來預測一架飛機在下一個時刻的到港延誤。
數據來源:美國交通部運輸統計局提供的公開的航班數據
代碼來源:https://www.evolutionarylearn.com/paper/python-keras-tensorflow-mts/
數據預處理
剔除掉航班取消和改航記錄
將數據整理成時間序列數據,也就是將計劃到港時間(年-月-日-時-分)作為數據表的索引
導入模塊
import?timeimport?math
import?numpy?as?np
import?pandas?as?pd
import?matplotlib.pyplot?as?plt
import?matplotlib.dates?as?mdates
from?datetime?import?datetime
from?keras.models?import?Sequential
from?keras.layers?import?LSTM,?Dense,?Dropout
from?sklearn.preprocessing?import?MinMaxScaler
from?sklearn.preprocessing?import?LabelEncoder
from?sklearn.preprocessing?import?OneHotEncoder
from?sklearn.metrics?import?r2_score
from?keras?import?backend?as?K??#?Keras解決OOM超內存問題
建立LSTM類
LSTM類的基本框架是初始化,數據集分割,網絡創建與訓練,網絡評估和結果可視化。
【初始化】:初始化主要是將基本的參數和數據導入進將要創建的實例。代碼如下:
????def?__init__(self,?dataset,?hyper_params):????????self.dataset?=?dataset??#?Initialize?data?sets/數據集初始化
????????self.num_neur?=?hyper_params[0]??#?Initialize?number?of?layer?and?number?of?neurons?in?each?layer/初始化隱層數和各層神經元個數
????????self.look_back?=?hyper_params[1]??#?Initialize?length?of?windows/初始化窗口長度
????????self.epochs?=?hyper_params[2]??#?Initialize?training?times/初始化訓練次數
????????self.batch_size?=?hyper_params[3]??#?Initialize?batch?size/初始化批數
????????self.selected_feature?=?hyper_params[4]??#?Initialize?the?selected?features/初始化選擇特征
????????self.train_ratio?=?hyper_params[5]??#?Initialize?the?splitted?ratio?of?training/初始化訓練集分割比例
????????self.feature_num?=?hyper_params[6]??#?Initialize?the?number?of?features/初始化特征數量
????????self.dropoutrate?=?hyper_params[7]
????????self.x_train?=?[]??#?Initialize?training?features?of?training?data?set/初始化訓練集x部分-訓練特征
????????self.y_train?=?[]??#?Initialize?supervisory?signals?of?training?data?set/初始化訓練集y部分-監督信號
????????self.x_test?=?[]??#?Initialize?test?features?of?training?data?set/初始化測試集x部分-測試特征
????????self.y_test?=?[]??#?Initialize?supervisory?signals?of?training?data?set/初始化測試集y部分-監督信號
【數據集分割】:數據集分割包括兩部分,一部分是特征選擇,一部分是分割測試集和訓練集。
????????def?create_dataset(dataset,?look_back):????????????dataX,?dataY?=?[],?[]
????????????for?i?in?range(len(dataset)?-?look_back):
????????????????a?=?dataset[i:(i?+?look_back),?0:dataset.shape[1]]
????????????????dataX.append(a)
????????????????dataY.append(dataset[i?+?look_back,?0])
????????????return?np.array(dataX),?np.array(dataY)
????????selected_list?=?feature_selection(self.selected_feature)??#?Index?list?of?selected?feature/選擇特征列表索引
????????train_size?=?int(len(self.dataset)?*?self.train_ratio)??#?Size?of?training?data?set/訓練集大小
????????train_data?=?self.dataset[0:train_size,?selected_list]??#?Training?data?set/訓練集
????????test_data?=?self.dataset[train_size?-?self.look_back?-?1:len(self.dataset),?selected_list]??#?Test?data?set/測試集
????????self.feature_num?=?len(selected_list)??#?Update?the?number?of?selected?feature/更新特征數量
????????#?Data?set?detail/具體分割后數據集
????????x_train,?self.y_train?=?create_dataset(train_data,?self.look_back)
????????x_test,?self.y_test?=?create_dataset(test_data,?self.look_back)
????????#?Reshape?input?to?be?[samples,?feature_num,?features]/整理特征數據的格式
????????self.x_train?=?np.reshape(x_train,?(x_train.shape[0],?self.feature_num,?x_train.shape[1]))
????????self.x_test?=?np.reshape(x_test,?(x_test.shape[0],?self.feature_num,?x_test.shape[1]))
這段代碼中的測試集劃分用的是test_data = self.dataset[train_size - self.look_back - 1:len(self.dataset), selected_list],為什么不是test_data = self.dataset[train_size :len(self.dataset), selected_list]呢?這個是為了保證測試集中有更多樣本,后面一種會由于存在窗口損失掉一部分數據,減一應該是為了作圖時連接訓練部分和測試部分。
【網絡創建】:開始在蛋糕架上插蛋糕~
????def?lstm(self):????????start_cr_a_fit_net?=?time.time()??#?Record?time/記錄網絡創建與訓練時間
????????self.split_dataset()??#?Split?the?data?set/數據分割
????????#?Create?and?fit?the?LSTM?network/創建并擬合LSTM網絡
????????LSTM_model?=?Sequential()
????????for?i?in?range(len(self.num_neur)):??#?構建多層網絡
????????????if?len(self.num_neur)?==?1:
????????????????LSTM_model.add(LSTM(self.num_neur[i],?input_shape=(None,?self.look_back),dropout=self.dropoutrate))
????????????else:
????????????????if?i?1:
????????????????????LSTM_model.add(LSTM(self.num_neur[i],?input_shape=(None,?self.look_back),?return_sequences=True))
????????????????????LSTM_model.add(Dropout(self.dropoutrate))
????????????????else:
????????????????????LSTM_model.add(LSTM(self.num_neur[i],?input_shape=(None,?self.look_back)))
????????LSTM_model.add(Dense(1))
????????LSTM_model.summary()??#?Summary?the?structure?of?neural?network/網絡結構總結
????????LSTM_model.compile(loss='mean_squared_error',?optimizer='adam')??#?Compile?the?neural?network/編譯網絡
????????LSTM_model.fit(self.x_train,?self.y_train,?epochs=self.epochs,?batch_size=self.batch_size
???????????????????????,?verbose=2)??#?Fit?the?LSTM?network/擬合LSTM網絡
????????end_cr_a_fit_net?=?time.time()?-?start_cr_a_fit_net
????????print('Running?time?of?creating?and?fitting?the?LSTM?network:?%.2f?Seconds'?%?(end_cr_a_fit_net))
????????#?LSTM?prediction/LSTM進行預測
????????trainPredict?=?LSTM_model.predict(self.x_train)??#?Predict?by?training?data?set/訓練集預測
????????testPredict?=?LSTM_model.predict(self.x_test)??#?Predict?by?test?data?set/測試集預測
????????return?trainPredict,?testPredict,?self.y_train,?self.y_test
【網絡評估】這里我們的評估指標選用的是。
????def?mape(self,?scaler,?trainPredict,?testPredict):????????#?Invert?predictions?start?/?將預測值轉換為正常數值
????????#?Create?empty?table?like?the?dataset/創建一個空的數組,?結構同dataset
????????trainPredict_dataset_like?=?np.zeros(shape=(len(trainPredict),?self.dataset.shape[1]))
????????#?Put?the?predicted?values?in?the?right?field/將預測值填充進新建數組
????????trainPredict_dataset_like[:,?0]?=?trainPredict[:,?0]
????????#?Inverse?transform?and?then?select?the?right?field/數據轉換
????????trainPredict?=?scaler.inverse_transform(trainPredict_dataset_like)[:,?0]
????????y_train_dataset_like?=?np.zeros(shape=(len(self.y_train),?self.dataset.shape[1]))
????????y_train_dataset_like[:,?0]?=?self.y_train
????????self.y_train?=?scaler.inverse_transform(y_train_dataset_like)[:,?0]
????????testPredict_dataset_like?=?np.zeros(shape=(len(testPredict),?self.dataset.shape[1]))
????????testPredict_dataset_like[:,?0]?=?testPredict[:,?0]
????????testPredict?=?scaler.inverse_transform(testPredict_dataset_like)[:,?0]
????????y_test_dataset_like?=?np.zeros(shape=(len(self.y_test),?self.dataset.shape[1]))
????????y_test_dataset_like[:,?0]?=?self.y_test
????????self.y_test?=?scaler.inverse_transform(y_test_dataset_like)[:,?0]
????????#?Invert?predictions?end/數據轉換結束
????????#?計算R2值
????????train_R2?=?r2_score(self.y_train,?trainPredict)
????????test_R2?=?r2_score(self.y_test,?testPredict)
????????#trainMAPE?=?np.mean(np.abs(self.y_train?-?trainPredict)?/?self.y_train)
????????#testMAPE?=?np.mean(np.abs(self.y_test?-?testPredict)?/?self.y_test)
????????print("Train?R2:?"?+?str(round(train_R2,?2)))
????????print("Test?R2:?"?+?str(round(test_R2,?2)))
????????return?trainPredict,?testPredict,?train_R2,?test_R2
【可視化】
????def?plot(self,?scaler,?trainPredict,?testPredict):????????#?Shift?training?predictions?for?plotting/轉換數據結構用于作圖-訓練預測結果
????????sub_traindataset?=?[[data]?for?data?in?self.dataset[:,?0]]
????????trainPredictPlot?=?np.empty_like(sub_traindataset)
????????trainPredictPlot[:,?0]?=?np.nan
????????trainPredictPlot[self.look_back:len(trainPredict)?+?self.look_back,?0]?=?trainPredict
????????#?Shift?test?predictions?for?plotting/轉換數據結構用于作圖-測試預測結果
????????sub_testdataset?=?[[data]?for?data?in?self.dataset[:,?0]]
????????testPredictPlot?=?np.empty_like(sub_testdataset)
????????testPredictPlot[:]?=?np.nan
????????testPredictPlot[len(trainPredict)?+?self.look_back?-?1:len(self.dataset),?0]?=?testPredict
????????#?plot?baseline?and?predictions/作圖
????????datasety_like?=?np.zeros(shape=(self.dataset.shape[0],?self.dataset.shape[1]))
????????datasety_like[:,?0]?=?self.dataset[:,?0]
????????y?=?scaler.inverse_transform(datasety_like)[:,?0]
????????#dates?=?pd.date_range('2010-12',?periods=len(y),?freq='M')
????????xs?=?[d?for?d?in?dataframe.index]
????????#?配置橫坐標
????????#plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
????????#plt.gca().xaxis.set_major_locator(mdates.MonthLocator(bymonth=[1,?7]))
????????A,?=?plt.plot(xs,?y[0:len(y)],?linewidth='2',?color='cornflowerblue')??#?真實值
????????B,?=?plt.plot(xs,?trainPredictPlot,?linewidth='1.5',?color='lightgreen')??#?LSTM訓練集結果
????????C,?=?plt.plot(xs,?testPredictPlot,?linewidth='4',?color='lightcoral')??#?LSTM測試集結果
????????#?plt.plot(NpredYPlot,linewidth?=?'3',color='k')
????????#plt.axvline(xs[76],?linewidth='2',?color='black')??#?畫直線區分訓練部分與測試部分
????????plt.legend((A,?B,?C),?('real_value',?'LSTM_train',?'LSTM_test'),?loc='best')
????????plt.gcf().autofmt_xdate()??#?自動旋轉日期標記
????????plt.xticks([])#由于時間太多,不顯示橫坐標軸
????????#plt.xlabel('Date',?family='Times?New?Roman',?fontsize=16)??#?X軸
????????plt.ylabel('Delay',?family='Times?New?Roman',?fontsize=16)??#?Y軸
????????plt.title('LSTM',?family='Times?New?Roman',?fontsize=16)??#?添加標題
????????#plt.savefig(r'C:\Users\10321\Desktop\result.png',?dpi=900)??#?保存圖片
????????plt.show()
????????del?trainPredictPlot,?testPredictPlot
導入參數
num_neur=[15, 10]表示這個LSTM網絡有兩個隱藏層,第一層的神經元個數為15,第二層的神經元個數為10;select_feature = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]表示我選擇了數據集中所有的特征,不選擇的設為0就好。所選特征包括:到港延誤、季度、周幾、出發機場、到達機場、計劃和實際運行時間、距離、在空時間、計劃過站時間、到達機場每小時的計劃離港流量和計劃到港流量。
if?__name__?==?"__main__":????#?Load?the?dataset/導入數據集
????file?=?r'E:/ZhangBo/data/aircraft_sequential_sarr.csv'
????dataframe?=?pd.read_csv(file,?index_col=0)
????dataframe?=?dataframe.dropna(axis=0,how='any')
????encoder?=?LabelEncoder()
????dataset?=?dataframe.values
????dataset[:,?3]?=?encoder.fit_transform(dataset[:,?3])
????dataset[:,?4]?=?encoder.fit_transform(dataset[:,?4])
????dataset?=?dataset.astype('float32')
????#?Normalize?the?dataset/標準化數據集
????scaler?=?MinMaxScaler(feature_range=(0,?1))
????dataset?=?scaler.fit_transform(dataset)
????#?Set?hyper-parameters/設定超參數
????num_neur?=?[15,10]??#?Number?of?layer?and?number?of?neurons?in?each?layer/隱藏層數和各層神經元個數
????look_back?=?15?#?Length?of?windows/窗口長度
????epochs?=?30??#?Training?times/訓練次數
????batch_size?=?10?#?Batch?size/批數大小
????select_feature?=?[1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1]#?Selected?features?list/被選擇特征列表
????train_ratio?=?0.832??#?Splitted?ratio?of?training?data?set/訓練集分割比例
????feature_num?=?dataset.shape[1]??#?Feature?number+y/特征數量+1,也將預測項作為特征
????dropoutrate?=?0.02
????#?Hyper-parameter?list/超參數列表
????hyper_params?=?[num_neur,?look_back,?epochs,?batch_size,?select_feature,?train_ratio,?feature_num,?dropoutrate]
????#?Start?an?LSTM?model/開始一個LSTM網絡
????model?=?lstm(dataset,?hyper_params)??#?Create?instance?of?LSTM/實例化模型
????trainPredict,?testPredict,?y_train,?y_test?=?model.lstm()??#?Create?and?fit?the?LSTM?network/創建并擬合LSTM網絡
????trainPredict,?testPredict,train_R2,?test_R2?=?model.mape(scaler,?trainPredict?,?testPredict)??#?Evaluate?network?performance/評估網絡效果
????model.plot(scaler,?trainPredict,?testPredict)??#?Visualization?results/可視化結果
????K.clear_session()??#?關掉內存中神經網絡
程序運行結果
【網絡結構】
【擬合網絡、訓練和測試結果】
我們創建和擬合LSTM網絡所需的時間為225.81秒,訓練集的值為0.55,測試集的值為0.44,可以看出,模型的預測結果并不是很好,因為這里我們并沒有對超參數進行選擇,而且航班延誤的一個很重要的影響因素——天氣的相關數據我們并沒有加進去。
本期結語
到這里,LSTM網絡的理論及其在交通建模中的應用的相關介紹就全部結束了。
如果你有問題和不同的看法,可以在后臺留言,我們互相交流,互相學習,共同進步~
編輯:莊楨
“交通科研Lab”:分享學習點滴,期待科研交流!
如果覺得還不錯
點這里!???
總結
以上是生活随笔為你收集整理的keras实现简单lstm_深度学习(LSTM)在交通建模中的应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python通过内置函数测试对象类型_P
- 下一篇: 有没有必要买python课_请问自学 P