在Python代寫中使用LSTM和PyTorch進行時間序列預測


原文鏈接: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()

輸出:

 

該數據集有三列:yearmonth,和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_datanumpy數組,則應該看到以下浮動類型值:

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_datanumpy數組中的最后12條記錄:

print(test_data)

輸出:

[417. 391. 419. 461. 472. 535. 622. 606. 508. 461. 390. 432.]

我們的數據集目前尚未規范化。最初幾年的乘客總數遠少於后來幾年的乘客總數。標准化數據以進行時間序列預測非常重要。以在一定范圍內的最小值和最大值之間對數據進行規范化。我們將使用模塊中的MinMaxScalersklearn.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.ModulePyTorch庫的類。 

 

讓我總結一下以上代碼中發生的事情。LSTM該類的構造函數接受三個參數:

  1. input_size:對應於輸入中的要素數量。盡管我們的序列長度為12,但每個月我們只有1個值,即乘客總數,因此輸入大小為1。
  2. hidden_layer_size:指定隱藏層的數量以及每層中神經元的數量。我們將有一層100個神經元。
  3. output_size:輸出中的項目數,由於我們要預測未來1個月的乘客人數,因此輸出大小為1。

接下來,在構造函數中,我們創建變量hidden_layer_sizelstmlinear,和hidden_cell。LSTM算法接受三個輸入:先前的隱藏狀態,先前的單元狀態和當前輸入。該hidden_cell變量包含先前的隱藏狀態和單元狀態。的lstmlinear層變量用於創建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使用時間序列數據進行未來的預測。 

 

 

 

如果您有任何疑問,請在下面發表評論。 

 


免責聲明!

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



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