LSTM長(zhǎng)短時(shí)神經(jīng)網(wǎng)絡(luò)預(yù)測(cè)航班序列
本文通過LSTM長(zhǎng)短時(shí)記憶神經(jīng)網(wǎng)絡(luò),來預(yù)測(cè)航班信息。
航班數(shù)據(jù)集來自https://github.com/mwaskom/seaborn-data的flights.csv
本文討論最多的問題:
1、本數(shù)據(jù)集分割存在數(shù)據(jù)泄漏。代碼取data_X, data_Y = create_dataset(dataset),根據(jù)設(shè)定的lookback可以獲得數(shù)據(jù)量為len(dataset)-lookback。然后代碼中對(duì)data_X和data_Y取70%做訓(xùn)練;確實(shí)代碼偽裝的很好,在于數(shù)據(jù)集的分割問題;在測(cè)試集中,[t1,t2]=>t3中,t1和t2是被泄露的。因?yàn)楝F(xiàn)實(shí)情況的t1和t2也需要模型進(jìn)行預(yù)測(cè);所以繪圖的效果會(huì)很好;
2、關(guān)于input_size和seq_len的問題,您說的是對(duì)的;本文的特征數(shù)為1,即當(dāng)月的航班預(yù)訂人數(shù);seq_len為2,是用了2天的數(shù)據(jù)。即特征數(shù)(input_size)為1,seq_len為2。
3、模型預(yù)測(cè)效果存在一小段的偏移,這是由lookback決定的;這個(gè)問題也是時(shí)間序列問題的痛點(diǎn);
庫(kù)導(dǎo)入
導(dǎo)入pytorch庫(kù)函數(shù)和散點(diǎn)圖庫(kù)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
導(dǎo)入數(shù)據(jù)并可視化
將航班數(shù)據(jù)導(dǎo)入,注意usecols=[1],選擇第2列數(shù)據(jù)。
data_csv = pd.read_csv('./data.csv',usecols=[1])
plt.plot(data_csv)

數(shù)據(jù)預(yù)處理
數(shù)據(jù)預(yù)處理,將數(shù)據(jù)中null或者缺項(xiàng)的列刪除。對(duì)數(shù)據(jù)集進(jìn)行歸一化處理,首先設(shè)置數(shù)據(jù)集為浮點(diǎn)類型,然后取數(shù)據(jù)集最大和最小項(xiàng)差值為放縮尺度,對(duì)每一個(gè)數(shù)據(jù)集數(shù)值進(jìn)行歸一化。
# 數(shù)據(jù)預(yù)處理
data_csv = data_csv.dropna() # 濾除缺失數(shù)據(jù)
dataset = data_csv.values # 獲得csv的值
dataset = dataset.astype('float32')
max_value = np.max(dataset) # 獲得最大值
min_value = np.min(dataset) # 獲得最小值
scalar = max_value - min_value # 獲得間隔數(shù)量
dataset = list(map(lambda x: x / scalar, dataset)) # 歸一化
設(shè)置數(shù)據(jù)集
設(shè)置X,Y數(shù)據(jù)集。以look_back=2為準(zhǔn),取第一個(gè)和第二個(gè)為數(shù)組,形成data_X,取第三個(gè)作為預(yù)測(cè)值,形成data_Y,完成訓(xùn)練集的提取。
def create_dataset(dataset, look_back=2):
dataX, dataY = [], []
for i in range(len(dataset) - look_back):
a = dataset[i:(i + look_back)]
dataX.append(a)
dataY.append(dataset[i + look_back])
return np.array(dataX), np.array(dataY)
# 創(chuàng)建好輸入輸出
data_X, data_Y = create_dataset(dataset)
設(shè)置訓(xùn)練集和測(cè)試集
取數(shù)據(jù)集的前70%作為訓(xùn)練集,后30%做為測(cè)試集。
# 劃分訓(xùn)練集和測(cè)試集,70% 作為訓(xùn)練集
train_size = int(len(data_X) * 0.7)
test_size = len(data_X) - train_size
train_X = data_X[:train_size]
train_Y = data_Y[:train_size]
test_X = data_X[train_size:]
test_Y = data_Y[train_size:]
設(shè)置LSTM模型數(shù)據(jù)類型形狀
設(shè)置LSTM能識(shí)別的數(shù)據(jù)類型,形成tran_X的一維兩個(gè)參數(shù)的數(shù)組,train_Y的一維一個(gè)參數(shù)的數(shù)組。并轉(zhuǎn)化為tensor類型
import torch
train_X = train_X.reshape(-1, 1, 2)
train_Y = train_Y.reshape(-1, 1, 1)
test_X = test_X.reshape(-1, 1, 2)
train_x = torch.from_numpy(train_X)
train_y = torch.from_numpy(train_Y)
test_x = torch.from_numpy(test_X)
建立LSTM模型
建立LSTM模型,第一層為L(zhǎng)STM神經(jīng)網(wǎng)絡(luò),第二層為一個(gè)全連接層。
from torch import nn
from torch.autograd import Variable
class lstm(nn.Module):
def __init__(self,input_size=2,hidden_size=4,output_size=1,num_layer=2):
super(lstm,self).__init__()
self.layer1 = nn.LSTM(input_size,hidden_size,num_layer)
self.layer2 = nn.Linear(hidden_size,output_size)
def forward(self,x):
x,_ = self.layer1(x)
s,b,h = x.size()
x = x.view(s*b,h)
x = self.layer2(x)
x = x.view(s,b,-1)
return x
model = lstm(2, 4,1,2)
建立損失函數(shù)和優(yōu)化器
設(shè)置交叉熵?fù)p失函數(shù)和自適應(yīng)梯度下降算法
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-2)
模型訓(xùn)練
# 開始訓(xùn)練
for e in range(1000):
var_x = Variable(train_x)
var_y = Variable(train_y)
# 前向傳播
out = model(var_x)
loss = criterion(out, var_y)
# 反向傳播
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (e + 1) % 100 == 0: # 每 100 次輸出結(jié)果
print('Epoch: {}, Loss: {:.5f}'.format(e + 1, loss.data[0]))
訓(xùn)練結(jié)果
Epoch: 100, Loss: 0.00785
Epoch: 200, Loss: 0.00641
Epoch: 300, Loss: 0.00518
Epoch: 400, Loss: 0.00356
Epoch: 500, Loss: 0.00248
Epoch: 600, Loss: 0.00429
Epoch: 700, Loss: 0.00226
Epoch: 800, Loss: 0.00231
Epoch: 900, Loss: 0.00210
Epoch: 1000, Loss: 0.00213
模型預(yù)測(cè)
model = model.eval() # 轉(zhuǎn)換成測(cè)試模式
data_X = data_X.reshape(-1, 1, 2)
data_X = torch.from_numpy(data_X)
var_data = Variable(data_X)
pred_test = model(var_data) # 測(cè)試集的預(yù)測(cè)結(jié)果
# 改變輸出的格式
pred_test = pred_test.view(-1).data.numpy()
預(yù)測(cè)序列可視化
# 畫出實(shí)際結(jié)果和預(yù)測(cè)的結(jié)果
plt.plot(pred_test, 'r', label='prediction')
plt.plot(dataset, 'b', label='real')
plt.legend(loc='best')
