原文鏈接:http://tecdat.cn/?p=8145
顧名思義,時間序列數據是一種隨時間變化的數據類型。例如,24小時內的溫度,一個月內各種產品的價格,一年中特定公司的股票價格。諸如長期短期記憶網絡(LSTM)之類的高級深度學習模型能夠捕獲時間序列數據中的模式,因此可用於對數據的未來趨勢進行預測。在本文中,您將看到如何使用LSTM算法使用時間序列數據進行將來的預測。
數據集和問題定義
讓我們先導入所需的庫,然后再導入數據集:
import torch
import torch.nn as nn
import seaborn as sns
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
讓我們打印 所有數據集的列表:
sns.get_dataset_names()
輸出:
['anscombe',
'attention',
'brain_networks',
'car_crashes',
'diamonds',
'dots',
'exercise',
'flights',
'fmri',
'gammas',
'iris',
'mpg',
'planets',
'tips',
'titanic']
讓我們將數據集加載到我們的應用程序中
flight_data = sns.load_dataset("flights")
flight_data.head()
輸出:
該數據集有三列:year
,month
,和passengers
。該passengers
列包含指定月份旅行旅客的總數。讓我們繪制數據集的形狀:
flight_data.shape
輸出:
(144, 3)
您可以看到數據集中有144行和3列,這意味着數據集包含12年的乘客旅行記錄。
任務是根據前132個月來預測最近12個月內旅行的乘客人數。請記住,我們有144個月的記錄,這意味着前132個月的數據將用於訓練我們的LSTM模型,而模型性能將使用最近12個月的值進行評估。
讓我們繪制每月乘客的出行頻率。
接下來的腳本繪制了每月乘客人數的頻率:
輸出:
輸出顯示,多年來,乘飛機旅行的平均乘客人數有所增加。一年內旅行的乘客數量波動,這是有道理的,因為在暑假或寒假期間,旅行的乘客數量與一年中的其他部分相比有所增加。
數據預處理
數據集中的列類型為object
,如以下代碼所示:
輸出:
Index(['year', 'month', 'passengers'], dtype='object')
第一步是將passengers
列的類型更改為float
。
all_data = flight_data['passengers'].values.astype(float)
現在,如果 打印all_data
numpy數組,則應該看到以下浮動類型值:
print(all_data)
輸出:
[112. 118. 132. 129. 121. 135. 148. 148. 136. 119. 104. 118. 115. 126.
141. 135. 125. 149. 170. 170. 158. 133. 114. 140. 145. 150. 178. 163.
172. 178. 199. 199. 184. 162. 146. 166. 171. 180. 193. 181. 183. 218.
230. 242. 209. 191. 172. 194. 196. 196. 236. 235. 229. 243. 264. 272.
237. 211. 180. 201. 204. 188. 235. 227. 234. 264. 302. 293. 259. 229.
203. 229. 242. 233. 267. 269. 270. 315. 364. 347. 312. 274. 237. 278.
284. 277. 317. 313. 318. 374. 413. 405. 355. 306. 271. 306. 315. 301.
356. 348. 355. 422. 465. 467. 404. 347. 305. 336. 340. 318. 362. 348.
363. 435. 491. 505. 404. 359. 310. 337. 360. 342. 406. 396. 420. 472.
548. 559. 463. 407. 362. 405. 417. 391. 419. 461. 472. 535. 622. 606.
508. 461. 390. 432.]
接下來,我們將數據集分為訓練集和測試集。LSTM算法將在訓練集上進行訓練。然后將使用該模型對測試集進行預測。將預測結果與測試集中的實際值進行比較,以評估訓練后模型的性能。
前132條記錄將用於訓練模型,后12條記錄將用作測試集。以下腳本將數據分為訓練集和測試集。
現在讓我們輸出測試和訓練集的長度:
輸出:
132
12
如果現在輸出測試數據,您將看到它包含all_data
numpy數組中的最后12條記錄:
print(test_data)
輸出:
[417. 391. 419. 461. 472. 535. 622. 606. 508. 461. 390. 432.]
我們的數據集目前尚未規范化。最初幾年的乘客總數遠少於后來幾年的乘客總數。標准化數據以進行時間序列預測非常重要。以在一定范圍內的最小值和最大值之間對數據進行規范化。我們將使用模塊中的MinMaxScaler
類sklearn.preprocessing
來擴展數據。
以下代碼 分別將最大值和最小值分別為-1和1歸一化。
輸出:
[[-0.96483516]
[-0.93846154]
[-0.87692308]
[-0.89010989]
[-0.92527473]]
[[1. ]
[0.57802198]
[0.33186813]
[0.13406593]
[0.32307692]]
您可以看到數據集值現在在-1和1之間。
在此重要的是要提到數據標准化僅應用於訓練數據,而不應用於測試數據。如果對測試數據進行歸一化處理,則某些信息可能會從訓練集中 到測試集中。
最后的預處理步驟是將我們的訓練數據轉換為序列和相應的標簽。
您可以使用任何序列長度,這取決於領域知識。但是,在我們的數據集中,使用12的序列長度很方便,因為我們有月度數據,一年中有12個月。如果我們有每日數據,則更好的序列長度應該是365,即一年中的天數。因此,我們將訓練的輸入序列長度設置為12。
接下來,我們將定義一個名為的函數create_inout_sequences
。該函數將接受原始輸入數據,並將返回一個元組列表。在每個元組中,第一個元素將包含與12個月內旅行的乘客數量相對應的12個項目的列表,第二個元組元素將包含一個項目,即在12 + 1個月內的乘客數量。
執行以下腳本以創建序列和相應的標簽進行訓練:
如果打印train_inout_seq
列表的長度,您將看到它包含120個項目。這是因為盡管訓練集包含132個元素,但是序列長度為12,這意味着第一個序列由前12個項目組成,第13個項目是第一個序列的標簽。同樣,第二個序列從第二個項目開始,到第13個項目結束,而第14個項目是第二個序列的標簽,依此類推。
現在讓我們輸出train_inout_seq
列表的前5個項目:
輸出:
[(tensor([-0.9648, -0.9385, -0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066,
-0.8593, -0.9341, -1.0000, -0.9385]), tensor([-0.9516])),
(tensor([-0.9385, -0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593,
-0.9341, -1.0000, -0.9385, -0.9516]),
tensor([-0.9033])),
(tensor([-0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341,
-1.0000, -0.9385, -0.9516, -0.9033]), tensor([-0.8374])),
(tensor([-0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341, -1.0000,
-0.9385, -0.9516, -0.9033, -0.8374]), tensor([-0.8637])),
(tensor([-0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341, -1.0000, -0.9385,
-0.9516, -0.9033, -0.8374, -0.8637]), tensor([-0.9077]))]
您會看到每個項目都是一個元組,其中第一個元素由序列的12個項目組成,第二個元組元素包含相應的標簽。
創建LSTM模型
我們已經對數據進行了預處理,現在是時候訓練我們的模型了。我們將定義一個類LSTM
,該類繼承自nn.Module
PyTorch庫的類。
讓我總結一下以上代碼中發生的事情。LSTM
該類的構造函數接受三個參數:
input_size
:對應於輸入中的要素數量。盡管我們的序列長度為12,但每個月我們只有1個值,即乘客總數,因此輸入大小為1。hidden_layer_size
:指定隱藏層的數量以及每層中神經元的數量。我們將有一層100個神經元。output_size
:輸出中的項目數,由於我們要預測未來1個月的乘客人數,因此輸出大小為1。
接下來,在構造函數中,我們創建變量hidden_layer_size
,lstm
,linear
,和hidden_cell
。LSTM算法接受三個輸入:先前的隱藏狀態,先前的單元狀態和當前輸入。該hidden_cell
變量包含先前的隱藏狀態和單元狀態。的lstm
和linear
層變量用於創建LSTM和線性層。
在forward
方法內部,將input_seq
作為參數傳遞,該參數首先傳遞給lstm
圖層。lstm
層的輸出是當前時間步的隱藏狀態和單元狀態,以及輸出。lstm
圖層的輸出將傳遞到該linear
圖層。預計的乘客人數存儲在predictions
列表的最后一項中,並返回到調用函數。
下一步是創建LSTM()
類的對象,定義損失函數和優化器。由於我們正在解決分類問題,
讓我們輸出模型:
輸出:
訓練模型
我們將訓練模型150個步長。
輸出:
epoch: 1 loss: 0.00517058
epoch: 26 loss: 0.00390285
epoch: 51 loss: 0.00473305
epoch: 76 loss: 0.00187001
epoch: 101 loss: 0.00000075
epoch: 126 loss: 0.00608046
epoch: 149 loss: 0.0004329932
由於默認情況下權重是在PyTorch神經網絡中隨機初始化的,因此您可能會獲得不同的值。
做出預測
現在我們的模型已經訓練完畢,我們可以開始進行預測了。
輸出:
[0.12527473270893097, 0.04615384712815285, 0.3274725377559662, 0.2835164964199066, 0.3890109956264496, 0.6175824403762817, 0.9516483545303345, 1.0, 0.5780220031738281, 0.33186814188957214, 0.13406594097614288, 0.32307693362236023]
您可以將上述值與train_data_normalized
數據列表的最后12個值進行比較。
該test_inputs
項目將包含12個項目。在for
循環內,這12個項目將用於對測試集中的第一個項目進行預測,即項目編號133。然后將預測值附加到test_inputs
列表中。在第二次迭代中,最后12個項目將再次用作輸入,並將進行新的預測,然后將其test_inputs
再次添加到列表中。for
由於測試集中有12個元素,因此該循環將執行12次。在循環末尾,test_inputs
列表將包含24個項目。最后12個項目將是測試集的預測值。
以下腳本用於進行預測:
如果輸出test_inputs
列表的長度,您將看到它包含24個項目。可以按以下方式打印最后12個預測項目:
輸出:
[0.4574652910232544,
0.9810629487037659,
1.279405951499939,
1.0621851682662964,
1.5830546617507935,
1.8899496793746948,
1.323508620262146,
1.8764172792434692,
2.1249167919158936,
1.7745600938796997,
1.7952896356582642,
1.977765679359436]
需要再次提及的是,根據用於訓練LSTM的權重,您可能會獲得不同的值。
由於我們對訓練數據集進行了標准化,因此預測值也進行了標准化。我們需要將歸一化的預測值轉換為實際的預測值。
actual_predictions = scaler.inverse_transform(np.array(test_inputs[train_window:] ).reshape(-1, 1))
print(actual_predictions)
輸出:
[[435.57335371]
[554.69182083]
[622.56485397]
[573.14712578]
[691.64493555]
[761.46355206]
[632.59821111]
[758.38493103]
[814.91857016]
[735.21242136]
[739.92839211]
[781.44169205]]
現在讓我們針對實際值繪制預測值。看下面的代碼:
x = np.arange(132, 144, 1)
print(x)
輸出:
[132 133 134 135 136 137 138 139 140 141 142 143]
在上面的腳本中,我們創建一個列表,其中包含最近12個月的數值。第一個月的索引值為0,因此最后一個月的索引值為143。
在下面的腳本中,我們將繪制144個月的乘客總數以及最近12個月的預計乘客數量。
plt.title('Month vs Passenger')
plt.ylabel('Total Passengers')
plt.grid(True)
plt.autoscale(axis='x', tight=True)
plt.plot(flight_data['passengers'])
plt.plot(x,actual_predictions)
plt.show()
輸出:
我們的LSTM所做的預測用橙色線表示。您可以看到我們的算法不太准確,但是它仍然能夠捕獲最近12個月內旅行的乘客總數的上升趨勢以及偶爾的波動。您可以嘗試在LSTM層中使用更多的時期和更多的神經元,以查看是否可以獲得更好的性能。
為了更好地查看輸出,我們可以繪制最近12個月的實際和預測乘客數量,如下所示:
plt.title('Month vs Passenger')
plt.ylabel('Total Passengers')
plt.grid(True)
plt.autoscale(axis='x', tight=True)
plt.plot(flight_data['passengers'][-train_window:])
plt.plot(x,actual_predictions)
plt.show()
輸出:
預測不是很准確,但是該算法能夠捕獲趨勢,即未來幾個月的乘客數量應高於前幾個月,且偶爾會有波動。
結論
LSTM是解決序列問題最廣泛使用的算法之一。在本文中,我們看到了如何通過LSTM使用時間序列數據進行未來的預測。