LSTM 原理
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math
from keras.models import Sequential
from keras.layers import Dense, LSTM
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
np.random.seed(7)
def create_dataset(dataset, look_back=1):
dataX, dataY = [], []
for i in range(len(dataset)-look_back-1):
a = dataset[i:(i+look_back), 0]
dataX.append(a)
dataY.append(dataset[i + look_back, 0])
return np.array(dataX), np.array(dataY)
dataframe = pd.read_csv('../input/traininggoogleprices/TrainPrices.csv', usecols=[1])
dataset = dataframe.values
dataset = dataset.astype('float32')
# normalize the dataset
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(dataset)
train_size = int(len(dataset) * 0.9)
test_size = len(dataset) - train_size
train, test = dataset[0:train_size,:], dataset[train_size:len(dataset),:]
look_back=1
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
# reshape input to be [samples, time steps, features]
trainX = np.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1]))
testX = np.reshape(testX, (testX.shape[0], 1, testX.shape[1]))
# create and fit the LSTM network
model = Sequential()
model.add(LSTM(128,activation='tanh', input_shape=(1, look_back), return_sequences=True))
model.add(LSTM(128,activation='tanh', input_shape=(1, look_back),return_sequences=False))
model.add(Dense(1, activation='relu'))
model.compile(loss='mse', optimizer='RMSProp', metrics = ['accuracy'])
model.fit(trainX, trainY, epochs=10, batch_size=32, verbose=2)
# make predictions
trainPredict = model.predict(trainX)
testPredict = model.predict(testX)
# invert predictions
trainPredict = scaler.inverse_transform(trainPredict)
trainY = scaler.inverse_transform([trainY])
testPredict = scaler.inverse_transform(testPredict)
testY = scaler.inverse_transform([testY])
# calculate root mean squared error
trainScore = math.sqrt(mean_squared_error(trainY[0], trainPredict[:,0]))
print('Train Score: %.2f RMSE' % (trainScore))
testScore = math.sqrt(mean_squared_error(testY[0], testPredict[:,0]))
print('Test Score: %.2f RMSE' % (testScore))
# shift train predictions for plotting
trainPredictPlot = np.empty_like(dataset)
trainPredictPlot[:, :] = np.nan
trainPredictPlot[look_back:len(trainPredict)+look_back, :] = trainPredict
# shift test predictions for plotting
testPredictPlot = np.empty_like(dataset)
testPredictPlot[:, :] = np.nan
testPredictPlot[len(trainPredict)+(look_back*2)+1:len(dataset)-1, :] = testPredict
# plot baseline and predictions
plt.plot(scaler.inverse_transform(dataset))
plt.plot(trainPredictPlot)
plt.plot(testPredictPlot)
plt.show()
多變量時(shí)間序列預(yù)測(cè)
諸如長期短期記憶(LSTM)復(fù)發(fā)神經(jīng)網(wǎng)絡(luò)的神經(jīng)網(wǎng)絡(luò)能夠幾乎無縫地模擬多個(gè)輸入變量的問題。這在時(shí)間序列預(yù)測(cè)中是一個(gè)很大的好處,其中古典線性方法難以適應(yīng)多變量或多輸入預(yù)測(cè)問題。
在本教程中,您將發(fā)現(xiàn)如何在Keras深度學(xué)習(xí)庫中開發(fā)多變量時(shí)間序列預(yù)測(cè)的LSTM模型。
如何將原始數(shù)據(jù)集轉(zhuǎn)換為可用于時(shí)間序列預(yù)測(cè)的內(nèi)容。
如何準(zhǔn)備數(shù)據(jù)并適應(yīng)多變量時(shí)間序列預(yù)測(cè)問題的LSTM。
如何做出預(yù)測(cè)并將結(jié)果重新調(diào)整到原始單位。
目錄
- 空氣污染預(yù)測(cè)
- 數(shù)據(jù)準(zhǔn)備
- 多變量時(shí)間序列預(yù)測(cè)
1. 空氣污染預(yù)測(cè)
數(shù)據(jù)包括日期時(shí)間,稱為PM2.5濃度的污染物,以及天氣信息,包括露點(diǎn),溫度,壓力,風(fēng)向,風(fēng)速和累積的降雪小時(shí)數(shù)。原始數(shù)據(jù)中的完整功能列表如下:
NO:行號(hào)
年:這一年的數(shù)據(jù)年
月份:這一行的數(shù)據(jù)月份
day:此行中的數(shù)據(jù)日
小時(shí):小時(shí)數(shù)據(jù)在這行
pm2.5:PM2.5濃度
DEWP:露點(diǎn)
溫度:溫度
PRES:壓力
cbwd:組合風(fēng)向
Iws:累積風(fēng)速
是:積雪時(shí)間
Ir:累積的下雨時(shí)數(shù)
我們可以使用這些數(shù)據(jù)并構(gòu)建一個(gè)預(yù)測(cè)問題,鑒于天氣條件和前幾個(gè)小時(shí)的污染,我們預(yù)測(cè)在下一個(gè)小時(shí)的污染。
Beijing PM2.5 Data Set
2,數(shù)據(jù)準(zhǔn)備
第一步是將日期時(shí)間信息整合為一個(gè)日期時(shí)間,以便我們可以將其用作熊貓的索引。
快速檢查顯示前24小時(shí)的pm2.5的NA值。因此,我們將需要?jiǎng)h除第一行數(shù)據(jù)。在數(shù)據(jù)集中還有幾個(gè)分散的“NA”值;我們現(xiàn)在可以用0值標(biāo)記它們。
以下腳本加載原始數(shù)據(jù)集,并將日期時(shí)間信息解析為Pandas DataFrame索引。 “No”列被刪除,然后為每列指定更清晰的名稱。最后,將NA值替換為“0”值,并刪除前24小時(shí)。
from pandas import read_csv
from datetime import datetime
# load data
def parse(x):
return datetime.strptime(x, '%Y %m %d %H')
dataset = read_csv('raw.csv', parse_dates = [['year', 'month', 'day', 'hour']], index_col=0, date_parser=parse)
dataset.drop('No', axis=1, inplace=True)
# manually specify column names
dataset.columns = ['pollution', 'dew', 'temp', 'press', 'wnd_dir', 'wnd_spd', 'snow', 'rain']
dataset.index.name = 'date'
# mark all NA values with 0
dataset['pollution'].fillna(0, inplace=True)
# drop the first 24 hours
dataset = dataset[24:]
# summarize first 5 rows
print(dataset.head(5))
# save to file
dataset.to_csv('pollution.csv')
然后可以對(duì)其畫圖來看他們的分布情況:
from pandas import read_csv
from matplotlib import pyplot
# load dataset
dataset = read_csv('pollution.csv', header=0, index_col=0)
values = dataset.values
# specify columns to plot
groups = [0, 1, 2, 3, 5, 6, 7]
i = 1
# plot each column
pyplot.figure()
for group in groups:
pyplot.subplot(len(groups), 1, i)
pyplot.plot(values[:, group])
pyplot.title(dataset.columns[group], y=0.5, loc='right')
i += 1
pyplot.show()

多元LSTM預(yù)測(cè)
第一步是為LSTM準(zhǔn)備污染數(shù)據(jù)集。
這涉及將數(shù)據(jù)集視為監(jiān)督學(xué)習(xí)問題并對(duì)輸入變量進(jìn)行歸一化。
考慮到上一個(gè)時(shí)間段的污染測(cè)量和天氣條件,我們將把監(jiān)督學(xué)習(xí)問題作為預(yù)測(cè)當(dāng)前時(shí)刻(t)的污染情況。
這個(gè)表述是直接的,只是為了這個(gè)演示。您可以探索的一些替代方案包括:
根據(jù)過去24小時(shí)的天氣情況和污染,預(yù)測(cè)下一個(gè)小時(shí)的污染。
預(yù)測(cè)下一個(gè)小時(shí)的污染,并給予下一個(gè)小時(shí)的“預(yù)期”天氣條件。
我們可以使用在博客文章中開發(fā)的series_to_supervised()函數(shù)來轉(zhuǎn)換數(shù)據(jù)集:
# convert series to supervised learning
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
n_vars = 1 if type(data) is list else data.shape[1]
df = DataFrame(data)
cols, names = list(), list()
# input sequence (t-n, ... t-1)
for i in range(n_in, 0, -1):
cols.append(df.shift(i))
names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
# forecast sequence (t, t+1, ... t+n)
for i in range(0, n_out):
cols.append(df.shift(-i))
if i == 0:
names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
else:
names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
# put it all together
agg = concat(cols, axis=1)
agg.columns = names
# drop rows with NaN values
if dropnan:
agg.dropna(inplace=True)
return agg
# load dataset
dataset = read_csv('pollution.csv', header=0, index_col=0)
values = dataset.values
# integer encode direction
encoder = LabelEncoder()
values[:,4] = encoder.fit_transform(values[:,4])
# ensure all data is float
values = values.astype('float32')
# normalize features
scaler = MinMaxScaler(feature_range=(0, 1))
scaled = scaler.fit_transform(values)
# frame as supervised learning
reframed = series_to_supervised(scaled, 1, 1)
# drop columns we don't want to predict
reframed.drop(reframed.columns[[9,10,11,12,13,14,15]], axis=1, inplace=True)
print(reframed.head())
這個(gè)數(shù)據(jù)準(zhǔn)備很簡(jiǎn)單,我們可以探索更多。您可以看到的一些想法包括:
one-hot 編碼。
使所有系列均勻分散和季節(jié)性調(diào)整。
提供超過1小時(shí)的輸入時(shí)間步長。
最后一點(diǎn)可能是最重要的,因?yàn)樵趯W(xué)習(xí)序列預(yù)測(cè)問題時(shí),LSTMs通過時(shí)間使用反向傳播。
定義和擬合模型
在本節(jié)中,我們將適合多變量輸入數(shù)據(jù)的LSTM。
首先,我們必須將準(zhǔn)備好的數(shù)據(jù)集分成列車和測(cè)試集。為了加快對(duì)這次示范的模式培訓(xùn),我們將僅適用于數(shù)據(jù)第一年的模型,然后對(duì)其余4年的數(shù)據(jù)進(jìn)行評(píng)估。如果您有時(shí)間,請(qǐng)考慮瀏覽此測(cè)試工具的倒置版本。
下面的示例將數(shù)據(jù)集分成列車和測(cè)試集,然后將列車和測(cè)試集分成輸入和輸出變量。最后,將輸入(X)重構(gòu)為LSTM預(yù)期的3D格式,即[樣本,時(shí)間步長,特征]。
# split into train and test sets
values = reframed.values
n_train_hours = 365 * 24
train = values[:n_train_hours, :]
test = values[n_train_hours:, :]
# split into input and outputs
train_X, train_y = train[:, :-1], train[:, -1]
test_X, test_y = test[:, :-1], test[:, -1]
# reshape input to be 3D [samples, timesteps, features]
train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))
test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))
print(train_X.shape, train_y.shape, test_X.shape, test_y.shape)
# design network
model = Sequential()
model.add(LSTM(50, input_shape=(train_X.shape[1], train_X.shape[2])))
model.add(Dense(1))
model.compile(loss='mae', optimizer='adam')
# fit network
history = model.fit(train_X, train_y, epochs=50, batch_size=72, validation_data=(test_X, test_y), verbose=2, shuffle=False)
# plot history
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()