Python中利用LSTM模型進行時間序列預(yù)測分析的實現(xiàn)
時間序列模型
時間序列預(yù)測分析就是利用過去一段時間內(nèi)某事件時間的特征來預(yù)測未來一段時間內(nèi)該事件的特征。這是一類相對比較復(fù)雜的預(yù)測建模問題,和回歸分析模型的預(yù)測不同,時間序列模型是依賴于事件發(fā)生的先后順序的,同樣大小的值改變順序后輸入模型產(chǎn)生的結(jié)果是不同的。
舉個栗子:根據(jù)過去兩年某股票的每天的股價數(shù)據(jù)推測之后一周的股價變化;根據(jù)過去2年某店鋪每周想消費人數(shù)預(yù)測下周來店消費的人數(shù)等等
RNN 和 LSTM 模型
時間序列模型最常用最強大的的工具就是遞歸神經(jīng)網(wǎng)絡(luò)(recurrent neural network, RNN)。相比與普通神經(jīng)網(wǎng)絡(luò)的各計算結(jié)果之間相互獨立的特點,RNN的每一次隱含層的計算結(jié)果都與當前輸入以及上一次的隱含層結(jié)果相關(guān)。通過這種方法,RNN的計算結(jié)果便具備了記憶之前幾次結(jié)果的特點。
典型的RNN網(wǎng)路結(jié)構(gòu)如下:

右側(cè)為計算時便于理解記憶而產(chǎn)開的結(jié)構(gòu)。簡單說,x為輸入層,o為輸出層,s為隱含層,而t指第幾次的計算;V,W,U為權(quán)重,其中計算第t次的隱含層狀態(tài)時為St = f(U*Xt + W*St-1),實現(xiàn)當前輸入結(jié)果與之前的計算掛鉤的目的。對RNN想要更深入的了解可以戳這里。
RNN的局限:
由于RNN模型如果需要實現(xiàn)長期記憶的話需要將當前的隱含態(tài)的計算與前n次的計算掛鉤,即St = f(U*Xt + W1*St-1 + W2*St-2 + ... + Wn*St-n),那樣的話計算量會呈指數(shù)式增長,導(dǎo)致模型訓(xùn)練的時間大幅增加,因此RNN模型一般直接用來進行長期記憶計算。
LSTM模型
LSTM(Long Short-Term Memory)模型是一種RNN的變型,最早由Juergen Schmidhuber提出的。經(jīng)典的LSTM模型結(jié)構(gòu)如下:

LSTM的特點就是在RNN結(jié)構(gòu)以外添加了各層的閥門節(jié)點。閥門有3類:遺忘閥門(forget gate),輸入閥門(input gate)和輸出閥門(output gate)。這些閥門可以打開或關(guān)閉,用于將判斷模型網(wǎng)絡(luò)的記憶態(tài)(之前網(wǎng)絡(luò)的狀態(tài))在該層輸出的結(jié)果是否達到閾值從而加入到當前該層的計算中。如圖中所示,閥門節(jié)點利用sigmoid函數(shù)將網(wǎng)絡(luò)的記憶態(tài)作為輸入計算;如果輸出結(jié)果達到閾值則將該閥門輸出與當前層的的計算結(jié)果相乘作為下一層的輸入(PS:這里的相乘是在指矩陣中的逐元素相乘);如果沒有達到閾值則將該輸出結(jié)果遺忘掉。每一層包括閥門節(jié)點的權(quán)重都會在每一次模型反向傳播訓(xùn)練過程中更新。更具體的LSTM的判斷計算過程如下圖所示:

LSTM模型的記憶功能就是由這些閥門節(jié)點實現(xiàn)的。當閥門打開的時候,前面模型的訓(xùn)練結(jié)果就會關(guān)聯(lián)到當前的模型計算,而當閥門關(guān)閉的時候之前的計算結(jié)果就不再影響當前的計算。因此,通過調(diào)節(jié)閥門的開關(guān)我們就可以實現(xiàn)早期序列對最終結(jié)果的影響。而當你不不希望之前結(jié)果對之后產(chǎn)生影響,比如自然語言處理中的開始分析新段落或新章節(jié),那么把閥門關(guān)掉即可。(對LSTM想要更具體的了解可以戳這里)
下圖具體演示了閥門是如何工作的:通過閥門控制使序列第1的輸入的變量影響到了序列第4,6的的變量計算結(jié)果。

黑色實心圓代表對該節(jié)點的計算結(jié)果輸出到下一層或下一次計算;空心圓則表示該節(jié)點的計算結(jié)果沒有輸入到網(wǎng)絡(luò)或者沒有從上一次收到信號。
Python中實現(xiàn)LSTM模型搭建
Python中有不少包可以直接調(diào)用來構(gòu)建LSTM模型,比如pybrain, kears, tensorflow, cikit-neuralnetwork等(更多戳這里)。這里我們選用keras。(PS:如果操作系統(tǒng)用的linux或者mac,強推Tensorflow!?。。?/p>
因為LSTM神經(jīng)網(wǎng)絡(luò)模型的訓(xùn)練可以通過調(diào)整很多參數(shù)來優(yōu)化,例如activation函數(shù),LSTM層數(shù),輸入輸出的變量維度等,調(diào)節(jié)過程相當復(fù)雜。這里只舉一個最簡單的應(yīng)用例子來描述LSTM的搭建過程。
應(yīng)用實例
基于某家店的某顧客的歷史消費的時間推測該顧客前下次來店的時間。具體數(shù)據(jù)如下所示:
消費時間 2015-05-15 14:03:51 2015-05-15 15:32:46 2015-06-28 18:00:17 2015-07-16 21:27:18 2015-07-16 22:04:51 2015-09-08 14:59:56 .. ..
具體操作:
1. 原始數(shù)據(jù)轉(zhuǎn)化
首先需要將時間點數(shù)據(jù)進行數(shù)值化。將具體時間轉(zhuǎn)化為時間段用于表示該用戶相鄰兩次消費的時間間隔,然后再導(dǎo)入模型進行訓(xùn)練是比較常用的手段。轉(zhuǎn)化后的數(shù)據(jù)如下:
消費間隔 0 44 18 0 54 .. ..
2.生成模型訓(xùn)練數(shù)據(jù)集(確定訓(xùn)練集的窗口長度)
這里的窗口指需要幾次消費間隔用來預(yù)測下一次的消費間隔。這里我們先采用窗口長度為3, 即用t-2, t-1,t次的消費間隔進行模型訓(xùn)練,然后用t+1次間隔對結(jié)果進行驗證。數(shù)據(jù)集格式如下:X為訓(xùn)練數(shù)據(jù),Y為驗證數(shù)據(jù)。
PS: 這里說確定也不太合適,因為窗口長度需要根據(jù)模型驗證結(jié)果進行調(diào)整的。
X1 X2 X3 Y 0 44 18 0 44 18 0 54 .. ..
注:直接這樣預(yù)測一般精度會比較差,可以把預(yù)測值Y根據(jù)數(shù)值bin到幾類,然后用轉(zhuǎn)換成one-hot標簽再來訓(xùn)練會比較好。比如如果把Y按數(shù)值范圍分到五類(1:0-20,2:20-40,3:40-60,4:60-80,5:80-100)上式可化為:
X1 X2 X3 Y 0 44 18 0 44 18 0 4 ...
Y轉(zhuǎn)化成one-hot以后則是(關(guān)于one-hot編碼可以參考這里)
1 0 0 0 0 0 0 0 0 1 ...
3. 網(wǎng)絡(luò)模型結(jié)構(gòu)的確定和調(diào)整
這里我們使用python的keras庫。(用java的同學(xué)可以參考下deeplearning4j這個庫)。網(wǎng)絡(luò)的訓(xùn)練過程設(shè)計到許多參數(shù)的調(diào)整:比如
需要確定LSTM模塊的激活函數(shù)(activation fucntion)(keras中默認的是tanh);
確定接收LSTM輸出的完全連接人工神經(jīng)網(wǎng)絡(luò)(fully-connected artificial neural network)的激活函數(shù)(keras中默認為linear);
確定每一層網(wǎng)絡(luò)節(jié)點的舍棄率(為了防止過度擬合(overfit)),這里我們默認值設(shè)定為0.2;
確定誤差的計算方式,這里我們使用均方誤差(mean squared error);
確定權(quán)重參數(shù)的迭代更新方式,這里我們采用RMSprop算法,通常用于RNN網(wǎng)絡(luò)。確定模型訓(xùn)練的epoch和batch size(關(guān)于模型的這兩個參數(shù)具體解釋戳這里)
一般來說LSTM模塊的層數(shù)越多(一般不超過3層,再多訓(xùn)練的時候就比較難收斂),對高級別的時間表示的學(xué)習能力越強;同時,最后會加一層普通的神經(jīng)網(wǎng)路層用于輸出結(jié)果的降維。典型結(jié)構(gòu)如下:

如果需要將多個序列進行同一個模型的訓(xùn)練,可以將序列分別輸入到獨立的LSTM模塊然后輸出結(jié)果合并后輸入到普通層。結(jié)構(gòu)如下:

4. 模型訓(xùn)練和結(jié)果預(yù)測
將上述數(shù)據(jù)集按4:1的比例隨機拆分為訓(xùn)練集和驗證集,這是為了防止過度擬合。訓(xùn)練模型。然后將數(shù)據(jù)的X列作為參數(shù)導(dǎo)入模型便可得到預(yù)測值,與實際的Y值相比便可得到該模型的優(yōu)劣。
實現(xiàn)代碼
時間間隔序列格式化成所需的訓(xùn)練集格式
import pandas as pd
import numpy as np
def create_interval_dataset(dataset, look_back):
"""
:param dataset: input array of time intervals
:param look_back: each training set feature length
:return: convert an array of values into a dataset matrix.
"""
dataX, dataY = [], []
for i in range(len(dataset) - look_back):
dataX.append(dataset[i:i+look_back])
dataY.append(dataset[i+look_back])
return np.asarray(dataX), np.asarray(dataY)
df = pd.read_csv("path-to-your-time-interval-file")
dataset_init = np.asarray(df) # if only 1 column
dataX, dataY = create_interval_dataset(dataset, lookback=3) # look back if the training set sequence length
這里的輸入數(shù)據(jù)來源是csv文件,如果輸入數(shù)據(jù)是來自數(shù)據(jù)庫的話可以參考這里
LSTM網(wǎng)絡(luò)結(jié)構(gòu)搭建
import pandas as pd
import numpy as np
import random
from keras.models import Sequential, model_from_json
from keras.layers import Dense, LSTM, Dropout
class NeuralNetwork():
def __init__(self, **kwargs):
"""
:param **kwargs: output_dim=4: output dimension of LSTM layer; activation_lstm='tanh': activation function for LSTM layers; activation_dense='relu': activation function for Dense layer; activation_last='sigmoid': activation function for last layer; drop_out=0.2: fraction of input units to drop; np_epoch=10, the number of epoches to train the model. epoch is one forward pass and one backward pass of all the training examples; batch_size=32: number of samples per gradient update. The higher the batch size, the more memory space you'll need; loss='mean_square_error': loss function; optimizer='rmsprop'
"""
self.output_dim = kwargs.get('output_dim', 8)
self.activation_lstm = kwargs.get('activation_lstm', 'relu')
self.activation_dense = kwargs.get('activation_dense', 'relu')
self.activation_last = kwargs.get('activation_last', 'softmax') # softmax for multiple output
self.dense_layer = kwargs.get('dense_layer', 2) # at least 2 layers
self.lstm_layer = kwargs.get('lstm_layer', 2)
self.drop_out = kwargs.get('drop_out', 0.2)
self.nb_epoch = kwargs.get('nb_epoch', 10)
self.batch_size = kwargs.get('batch_size', 100)
self.loss = kwargs.get('loss', 'categorical_crossentropy')
self.optimizer = kwargs.get('optimizer', 'rmsprop')
def NN_model(self, trainX, trainY, testX, testY):
"""
:param trainX: training data set
:param trainY: expect value of training data
:param testX: test data set
:param testY: epect value of test data
:return: model after training
"""
print "Training model is LSTM network!"
input_dim = trainX[1].shape[1]
output_dim = trainY.shape[1] # one-hot label
# print predefined parameters of current model:
model = Sequential()
# applying a LSTM layer with x dim output and y dim input. Use dropout parameter to avoid overfitting
model.add(LSTM(output_dim=self.output_dim,
input_dim=input_dim,
activation=self.activation_lstm,
dropout_U=self.drop_out,
return_sequences=True))
for i in range(self.lstm_layer-2):
model.add(LSTM(output_dim=self.output_dim,
input_dim=self.output_dim,
activation=self.activation_lstm,
dropout_U=self.drop_out,
return_sequences=True))
# argument return_sequences should be false in last lstm layer to avoid input dimension incompatibility with dense layer
model.add(LSTM(output_dim=self.output_dim,
input_dim=self.output_dim,
activation=self.activation_lstm,
dropout_U=self.drop_out))
for i in range(self.dense_layer-1):
model.add(Dense(output_dim=self.output_dim,
activation=self.activation_last))
model.add(Dense(output_dim=output_dim,
input_dim=self.output_dim,
activation=self.activation_last))
# configure the learning process
model.compile(loss=self.loss, optimizer=self.optimizer, metrics=['accuracy'])
# train the model with fixed number of epoches
model.fit(x=trainX, y=trainY, nb_epoch=self.nb_epoch, batch_size=self.batch_size, validation_data=(testX, testY))
# store model to json file
model_json = model.to_json()
with open(model_path, "w") as json_file:
json_file.write(model_json)
# store model weights to hdf5 file
if model_weight_path:
if os.path.exists(model_weight_path):
os.remove(model_weight_path)
model.save_weights(model_weight_path) # eg: model_weight.h5
return model
這里寫的只涉及LSTM網(wǎng)絡(luò)的結(jié)構(gòu)搭建,至于如何把數(shù)據(jù)處理規(guī)范化成網(wǎng)絡(luò)所需的結(jié)構(gòu)以及把模型預(yù)測結(jié)果與實際值比較統(tǒng)計的可視化,就需要根據(jù)實際情況做調(diào)整了。具體腳本可以參考下這個
參考文檔:
[力推]: Understanding LSTMs
What is batch size in neural network?
Time Series Prediction with LSTM Recurrent Neural Networks in Python with Keras
Save Your Neural Network Model to JSON
RECURRENT NEURAL NETWORKS TUTORIAL, PART 1 – INTRODUCTION TO RNNS
A Beginner's Guide to Recurrent Networks and LSTMs
Pybrain time series prediction using LSTM recurrent nets
Recurrent neural network for predicting next value in a sequence
What are some good Python libraries that implement LSTM networks?
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習有所幫助,也希望大家多多支持腳本之家。
- python實現(xiàn)BP神經(jīng)網(wǎng)絡(luò)回歸預(yù)測模型
- Python PaddleOCR模型訓(xùn)練及使用超詳細教程
- Python時間序列處理之ARIMA模型的使用講解
- Python使用Ollama實現(xiàn)私有大模型知識庫
- python 機器學(xué)習之支持向量機非線性回歸SVR模型
- 用Python給文本創(chuàng)立向量空間模型的教程
- python使用tensorflow保存、加載和使用模型的方法
- python構(gòu)建指數(shù)平滑預(yù)測模型示例
- Python深度學(xué)習之Unet?語義分割模型(Keras)
- 深入淺析Python 中的sklearn模型選擇
- Python深度學(xué)習時序預(yù)測:從數(shù)據(jù)預(yù)處理到DGCRN/Informer模型對比
相關(guān)文章
使用Python向DataFrame中指定位置添加一列或多列的方法
今天小編就為大家分享一篇使用Python向DataFrame中指定位置添加一列或多列的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-01-01
Python Charles抓包配置實現(xiàn)流程圖解
這篇文章主要介紹了Python Charles抓包實現(xiàn)流程圖解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友可以參考下2020-09-09
opencv+playwright滑動驗證碼的實現(xiàn)
滑動驗證碼是常見的驗證碼之一,本文主要介紹了opencv+playwright滑動驗證碼的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2023-11-11
利用Python對中國500強排行榜數(shù)據(jù)進行可視化分析
這篇文章主要介紹了利用Python對中國500強排行榜數(shù)據(jù)進行可視化分析,從不同角度去對數(shù)據(jù)進行統(tǒng)計分析,可視化展示,下文詳細內(nèi)容介紹需要的小伙伴可以參考一下2022-05-05
JupyterNotebook 輸出窗口的顯示效果調(diào)整方法
這篇文章主要介紹了JupyterNotebook 輸出窗口的顯示效果調(diào)整方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
Python使用matplotlib填充圖形指定區(qū)域代碼示例
這篇文章主要介紹了Python使用matplotlib填充圖形指定區(qū)域代碼示例,具有一定借鑒價值,需要的朋友可以參考下2018-01-01
Pandas將列表(List)轉(zhuǎn)換為數(shù)據(jù)框(Dataframe)
這篇文章主要介紹了Pandas將列表(List)轉(zhuǎn)換為數(shù)據(jù)框(Dataframe),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2020-04-04

