原文鏈接:
https://stackabuse.com/time-series-prediction-using-lstm-with-pytorch-in-python/
時間序列數據,顧名思義是一種隨時間變化的數據類型。例如,24小時時間段內的溫度,一個月內各種產品的價格,一個特定公司一年的股票價格。高級的深度學習模型,如長短期記憶網絡(LSTM),能夠捕捉時間序列數據中的模式,因此可以用來預測數據的未來趨勢。在本文中,您將看到如何使用LSTM算法使用時間序列數據進行未來預測。
Dataset and Problem Definition
我們將使用的數據集內置在Python Seaborn庫中。讓我們先導入所需的庫,然后再導入數據集:
1 import torch 2 import torch.nn as nn 3 4 import seaborn as sns 5 import numpy as np 6 import pandas as pd 7 import matplotlib.pyplot as plt 8 %matplotlib inline
讀入數據
1 import pandas as pd 2 flight_data = pd.read_csv('./data/flights.csv') #或者flight_data = sns.load_datasets("flights") 3 flight_data.head()
輸出:

flight_data.shape
#輸出: (144,3)
數據集有三列:year、month以及passengers,包含了12年的乘客出行紀錄;
任務:
根據面132個月的出行數據預測后12個月的出行數據;
繪制每個月的乘客出行頻率:
1 plt.plot(flight_data['passengers']) 2 plt.grid(True) 3 plt.title("Month vs passenger") 4 plt.ylabel("Total passengers") 5 plt.xlabel("Months") 6 plt.autoscale(axis='x',tight=True)

從輸出結果中可以看出,每年的乘客數量是在逐漸遞增的;
在同一年內,乘客的數量是波動的,這是符合常識的,因為在節假日的時候,乘客的數量相較於一年中的其他日子是會變多的;
數據預處理:
首先,看一下數據集中的列的數據類型:
1 flight_data.columns
輸出:
all_data = flight_data['passengers'].values.astype(float)
接下來,將數據集划分為訓練數據集和驗證數據集:
test_data_size = 12 train_data = all_data[:-test_data_size] #size=132 test_data = all_data[-test_data_size:] #size=12
此時,數據集並沒有經過標准化處理;
但是乘客數量在剛開始的年份要遠小於近兩年的數量;
我們將使用Min/max進行標准化;
1 from sklearn.preprocessing import MinMaxScaler 2 3 scaler = MinMaxScaler(feature_range=(-1,1)) 4 train_data_normalized = scaler.fit_transform(train_data.reshape(-1,1))
之后,將其轉化為tensor的數據形式:
train_data_normalized = torch.FloatTensor(train_data_normalized).view(-1) #轉換成1維張量
最后,就是將數據處理成sequences和對應標簽的形式;
在這里,我們取時間窗口為12,因為一年有12個月,這個是比較合理的;
1 train_window=12 2 3 def create_inout_sequences(input_data,tw): 4 inout_seq = [] 5 L = len(input_data) 6 for i in range(L-tw): 7 train_seq = input_data[i:i+tw] 8 train_label = input_data[i+tw:i+tw+1] 9 inout_seq.append((train_seq,train_label)) 10 return inout_seq 11 12 train_inout_seq = create_inout_sequences(train_data_normalized,train_window)
#一共有120個樣本 132-12=120
創建LSTM模型:
1 class LSTM(nn.Module): 2 def __init__(self, input_size=1,hidden_layer_size=100,output_size=1): 3 super().__init__() 4 5 self.hidden_layer = hidden_layer_size 6 self.lstm = nn.LSTM(input_size,hidden_layer_size) 7 self.linear = nn.linear(hidden_layer_size,uotput_size) 8 self.hidden_cell = (torch.zeros(1,1,self.hidden_layer_size), 9 torch.zeros(1,1,self.hidden_layer_size)) 10 def forward(self, input_seq): 11 lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq),1,-1), self.hidden_cell) 12 predictions = self.linear(lstm_out.view(len(input_seq),-1)) 13 return predictions[-1]
input_size:對應的輸入數據特征; 雖然我們的序列長度是12,但是對於每個月來說,我們只有1個值,例如,乘客的總數量,因此輸入的size是1;
hidden_layer_size: 每層的神經元的數量,我們每層一共有100個神經元;
output_size:預測下一個月的輸出數量,輸出的size為1;
之后我們創建hidden_layer_size, lstm, linear 以及hidden_cell。
LSTM算法接收三個輸入:之前的輸入狀態;之前的的cell狀態以及當前的輸入;
hidden_cell變量包含了先前的隱藏狀態和cell狀態;
lstm和linear層變量,用於創建LSTM和線性層;
在forward()算法中,使用input_seq作為輸入參數,首先被傳遞給lstm;
lstm的輸出,包含了當前時間戳下的隱藏層和細胞狀態,以及輸出;
lstm層的輸出被傳遞給Linear層,預測的乘客數量,就是predictions的最后一項;
1 model = LSTM() 2 loss_function = nn.MSELoss() 3 optimizer = torch.optim.Adam(model.parameters(),lr=0.001)
1 # 模型的訓練 2 epochs = 15 3 4 for i in range(epochs): 5 for seq, labels in train_inout_seq: 6 optimizer.zero_grad() 7 model.hidden_cell = (torch.zeros(1,1,model.hidden_layer_size), 8 torch.zeros(1,1,model.hidden_layer_size)) 9 10 y_pred = model(seq) 11 12 single_loss = loss_function(y_pred, labels) 13 single_loss.backward() 14 optimizer.step() 15 16 if i%2 ==1 : 17 print(f'epoch:{i:3} loss:{single_loss.item():10.8f}') 18 print(f'epoch:{i:3} loss:{single_loss.item():10.8f}')
模型的預測:
1 # 預測: 2 fut_pre = 12 3 4 test_inputs = train_data_normalized[-train_window:].tolist() 5 print(test_inputs) 6 7 model.eval() 8 for i in range(fut_pre): 9 seq = torch.FloatTensor(test_inputs[-train_window:]) 10 with torch.no_grad(): 11 model.hidden = (torch.zeros(1,1,model.hidden_layer_size), 12 torch.zeros(1,1,model.hidden_layer_size)) 13 14 test_inputs.append(model(seq).item())

