基于Keras的LSTM多变量时间序列股票预测

朋友多次劝我,用大数据人工智能研究下金融股票,由于本人水平有限,一直没有去想。最近两天,突然想到LSTM是不是很适合做股票预测。通过上网学习,还是真有案例。

适合多输入变量的神经网络模型一直让开发人员很头痛,但基于(LSTM)的循环神经网络能够几乎可以完美的解决多个输入变量的问题。基于(LSTM)的循环神经网络可以很好的利用在时间序列预测上,

长短期记忆循环神经网络等几乎可以完美地模拟多个输入变量的问题,这为时间序列预测带来极大益处。本文介绍了如何在 Keras 深度学习库中搭建用于多变量时间序列预测的 LSTM 模型。

因为市场总是会出现黑天鹅事件,比如股灾,这种不符合规律的事件是很难预测的,本文仅适用学习人工智能技术练习,“当你进入股市后,趋势就变化了”。

Keras是一个高度封装的神经网络框架,提供参数化的API,Keras由纯Python编写而成并基Tensorflow、Theano以及CNTK后端。Keras 为支持快速实验而生,能够把你的idea迅速转换为结果。

关于LSTM

LSTM算法的全称是长短期记忆网络(long short-term memory),由于LSTM算法基于RNN算法改进而来的,一种特殊的RNN网络,规避了标准RNN中梯度爆炸和梯度消失的问题,而且该网络设计出来是为了解决长依赖问题。该网络由 Hochreiter & Schmidhuber (1997)引入,并有许多人对其进行了改进和普及。他们的工作被用来解决了各种各样的问题,直到目前还被广泛应用。

多层LSTM只是将单个cell进行堆叠。LSTM模型为什么比CNN难理解呢?因为它把神经元的数量都藏到cell里面。通过对比CNN,看上面的图是不是有点感觉呢?一个cell其实就是一层神经元,只是LSTM和CNN不同的是,它的每一层t时刻的输出和t-1时刻的状态有关。也就是说当前cell的输出ht不仅仅影响到下一cell(图中右边的那列),还影响本cell下一时刻的状态和输出(图中按时间顺序堆叠的三个绿色的cell)。

理解到这一点了,我们也自然地理解到,xt可以是多维的。然后每个cell的hidden_size都可以进行设置。

数据源来自 这里 。

LSTM多变量时间序列股票预测”’Created on 2020年4月5日@author: xiaoyw”’import numpy as npimport matplotlib.pyplot as pltimport pandas as pdfrom sklearn.preprocessing import MinMaxScalerfrom keras.models import Sequential #Sequential 用于初始化神经网络from keras.layers import Dense #Dense 用于添加全连接的神经网络层from keras.layers import LSTM #LSTM 用于添加长短期内存层from keras.layers import Dropout #Dropout 用于添加防止过拟合的dropout层#构建训练数据def train_data(): dataset_train = pd.read_csv(‘NSE-TATAGLOBAL.csv’) training_set = dataset_train.iloc[:, 1:7].values dataset_train.head() sc = MinMaxScaler(feature_range = (0, 1)) training_set_scaled = sc.fit_transform(training_set) X_train = [] y_train = [] for i in range(60, 2035): X_train.append(training_set_scaled[i-60:i, :]) y_train.append(training_set_scaled[i, :]) X_train, y_train = np.array(X_train), np.array(y_train) X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 6)) return X_train,y_train,dataset_train,sc#构建测试数据def test_data(dataset_train,sc): dataset_test = pd.read_csv(‘tatatest.csv’) real_stock_price = dataset_test.iloc[:, 1:2].values #合并训练集和测试集 dataset_total = pd.concat((dataset_train, dataset_test), axis = 0) db_all = dataset_total.iloc[:, 1:7].values inputs = db_all[len(dataset_total) – len(dataset_test) – 60:] inputs = inputs.reshape(-1,6) inputs = sc.transform(inputs) X_test = [] for i in range(60, 76): X_test.append(inputs[i-60:i, :]) #X_test.append(inputs[i-60:i, 0]) X_test = np.array(X_test) X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 6)) return X_test,real_stock_price#创建股票预测模型def stock_model(X_train, y_train): regressor = Sequential() #LSTM的输入为 [samples, timesteps, features],这里的timesteps为步数,features为维度 这里我们的数据是6维的 regressor.add(LSTM(units = 50, return_sequences = True, input_shape = (X_train.shape[1], 6))) regressor.add(Dropout(0.2)) regressor.add(LSTM(units = 50, return_sequences = True)) regressor.add(Dropout(0.2)) regressor.add(LSTM(units = 50, return_sequences = True)) regressor.add(Dropout(0.2)) regressor.add(LSTM(units = 50)) regressor.add(Dropout(0.2)) #全连接,输出6个 regressor.add(Dense(units = 6)) regressor.compile(optimizer = ‘adam’, loss = ‘mean_squared_error’) regressor.fit(X_train, y_train, epochs = 100, batch_size = 32) return regressordef main(): X_train, y_train,dataset_train,sc = train_data() regressor = stock_model(X_train, y_train) X_test,real_stock_price = test_data(dataset_train,sc) predicted_stock_price = regressor.predict(X_test) predicted_stock_price = sc.inverse_transform(predicted_stock_price) plt.plot(real_stock_price, color = ‘black’, label = ‘TATA Stock Price’) #显示开盘价 plt.plot(predicted_stock_price[:,0], color = ‘green’, label = ‘Predicted TATA Stock Price’) plt.title(‘TATA Stock Price Prediction’) plt.xlabel(‘Time’) plt.ylabel(‘TATA Stock Price’) plt.legend() plt.show()if __name__ == ‘__main__’: main()

参考源代码为单变量(开盘价)预测,效果如下左侧图所示,改造成本文代码,为多变量输入并且多维度输出,预测效果(取开盘价)如下右侧图所示。

关于本文技术和代码分析,请关注后续内容分享。

基于Keras的LSTM多变量时间序列股票预测

如何用 Keras 调试LSTM超参数解决时间序列预测问题

就一个abcd作为一条样本即可,a b c d 的每一步都会计算loss的,所以拆开也没啥用 另外你这个不是序列标注,因为你是要预测下一个,而不是给整体一个最佳序列

基于Keras的LSTM多变量时间序列股票预测

如何在Python中用LSTM网络进行时间序列预测

时间序列模型

时间序列预测分析就是利用过去一段时间内某事件时间的特征来预测未来一段时间内该事件的特征。这是一类相对比较复杂的预测建模问题,和回归分析模型的预测不同,时间序列模型是依赖于事件发生的先后顺序的,同样大小的值改变顺序后输入模型产生的结果是不同的。
举个栗子:根据过去两年某股票的每天的股价数据推测之后一周的股价变化;根据过去2年某店铺每周想消费人数预测下周来店消费的人数等等

RNN 和 LSTM 模型

时间序列模型最常用最强大的的工具就是递归神经网络(recurrent neural network, RNN)。相比与普通神经网络的各计算结果之间相互独立的特点,RNN的每一次隐含层的计算结果都与当前输入以及上一次的隐含层结果相关。通过这种方法,RNN的计算结果便具备了记忆之前几次结果的特点。

典型的RNN网路结构如下:
右侧为计算时便于理解记忆而产开的结构。简单说,x为输入层,o为输出层,s为隐含层,而t指第几次的计算;V,W,U为权重,其中计算第t次的隐含层状态时为St = f(U*Xt + W*St-1),实现当前输入结果与之前的计算挂钩的目的。对RNN想要更深入的了解可以戳这里。

RNN的局限:
由于RNN模型如果需要实现长期记忆的话需要将当前的隐含态的计算与前n次的计算挂钩,即St = f(U*Xt + W1*St-1 + W2*St-2 + … + Wn*St-n),那样的话计算量会呈指数式增长,导致模型训练的时间大幅增加,因此RNN模型一般直接用来进行长期记忆计算。

LSTM模型
LSTM(Long Short-Term Memory)模型是一种RNN的变型,最早由Juergen Schmidhuber提出的。经典的LSTM模型结构如下:
LSTM的特点就是在RNN结构以外添加了各层的阀门节点。阀门有3类:遗忘阀门(forget gate),输入阀门(input gate)和输出阀门(output gate)。这些阀门可以打开或关闭,用于将判断模型网络的记忆态(之前网络的状态)在该层输出的结果是否达到阈值从而加入到当前该层的计算中。如图中所示,阀门节点利用sigmoid函数将网络的记忆态作为输入计算;如果输出结果达到阈值则将该阀门输出与当前层的的计算结果相乘作为下一层的输入(PS:这里的相乘是在指矩阵中的逐元素相乘);如果没有达到阈值则将该输出结果遗忘掉。每一层包括阀门节点的权重都会在每一次模型反向传播训练过程中更新。更具体的LSTM的判断计算过程如下图所示:
LSTM模型的记忆功能就是由这些阀门节点实现的。当阀门打开的时候,前面模型的训练结果就会关联到当前的模型计算,而当阀门关闭的时候之前的计算结果就不再影响当前的计算。因此,通过调节阀门的开关我们就可以实现早期序列对最终结果的影响。而当你不不希望之前结果对之后产生影响,比如自然语言处理中的开始分析新段落或新章节,那么把阀门关掉即可。(对LSTM想要更具体的了解可以戳这里)
下图具体演示了阀门是如何工作的:通过阀门控制使序列第1的输入的变量影响到了序列第4,6的的变量计算结果。
黑色实心圆代表对该节点的计算结果输出到下一层或下一次计算;空心圆则表示该节点的计算结果没有输入到网络或者没有从上一次收到信号。

Python中实现LSTM模型搭建

Python中有不少包可以直接调用来构建LSTM模型,比如pybrain, kears, tensorflow, cikit-neuralnetwork等(更多戳这里)。这里我们选用keras。(PS:如果操作系统用的linux或者mac,强推Tensorflow!!!)

因为LSTM神经网络模型的训练可以通过调整很多参数来优化,例如activation函数,LSTM层数,输入输出的变量维度等,调节过程相当复杂。这里只举一个最简单的应用例子来描述LSTM的搭建过程。

应用实例

基于某家店的某顾客的历史消费的时间推测该顾客前下次来店的时间。具体数据如下所示:

消费时间
2015-05-15 14:03:512015-05-15 15:32:462015-06-28 18:00:172015-07-16 21:27:182015-07-16 22:04:512015-09-08 14:59:56..
..

具体操作:
1. 原始数据转化
首先需要将时间点数据进行数值化。将具体时间转化为时间段用于表示该用户相邻两次消费的时间间隔,然后再导入模型进行训练是比较常用的手段。转化后的数据如下:

消费间隔04418054..
..

2.生成模型训练数据集(确定训练集的窗口长度)
这里的窗口指需要几次消费间隔用来预测下一次的消费间隔。这里我们先采用窗口长度为3, 即用t-2, t-1,t次的消费间隔进行模型训练,然后用t+1次间隔对结果进行验证。数据集格式如下:X为训练数据,Y为验证数据。
PS: 这里说确定也不太合适,因为窗口长度需要根据模型验证结果进行调整的。

X1    X2    X3    Y0    44    18    044    18    0    54..
..    

注:直接这样预测一般精度会比较差,可以把预测值Y根据数值bin到几类,然后用转换成one-hot标签再来训练会比较好。比如如果把Y按数值范围分到五类(1:0-20,2:20-40,3:40-60,4:60-80,5:80-100)上式可化为:

X1    X2    X3    Y0    44    18    044    18    0    4…

Y转化成one-hot以后则是(关于one-hot编码可以参考这里)

1    0    0    0    00    0    0    0    1…

3. 网络模型结构的确定和调整
这里我们使用python的keras库。(用java的同学可以参考下deeplearning4j这个库)。网络的训练过程设计到许多参数的调整:比如

需要确定LSTM模块的激活函数(activation fucntion)(keras中默认的是tanh);

确定接收LSTM输出的完全连接人工神经网络(fully-connected artificial neural network)的激活函数(keras中默认为linear);

确定每一层网络节点的舍弃率(为了防止过度拟合(overfit)),这里我们默认值设定为0.2;

确定误差的计算方式,这里我们使用均方误差(mean squared error);

确定权重参数的迭代更新方式,这里我们采用RMSprop算法,通常用于RNN网络。

确定模型训练的epoch和batch size(关于模型的这两个参数具体解释戳这里)
一般来说LSTM模块的层数越多(一般不超过3层,再多训练的时候就比较难收敛),对高级别的时间表示的学习能力越强;同时,最后会加一层普通的神经网路层用于输出结果的降维。典型结构如下:
如果需要将多个序列进行同一个模型的训练,可以将序列分别输入到独立的LSTM模块然后输出结果合并后输入到普通层。结构如下:

4. 模型训练和结果预测
将上述数据集按4:1的比例随机拆分为训练集和验证集,这是为了防止过度拟合。训练模型。然后将数据的X列作为参数导入模型便可得到预测值,与实际的Y值相比便可得到该模型的优劣。

实现代码

时间间隔序列格式化成所需的训练集格式

import pandas as pdimport numpy as npdef 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 columndataX, dataY = create_interval_dataset(dataset, lookback=3)    # look back if the training set sequence length

这里的输入数据来源是csv文件,如果输入数据是来自数据库的话可以参考这里

LSTM网络结构搭建

import pandas as pdimport numpy as npimport randomfrom keras.models import Sequential, model_from_jsonfrom keras.layers import Dense, LSTM, Dropoutclass 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 youll 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网络的结构搭建,至于如何把数据处理规范化成网络所需的结构以及把模型预测结果与实际值比较统计的可视化,就需要根据实际情况做调整了。

未经允许不得转载:股市行情网 » 基于Keras的LSTM多变量时间序列股票预测

相关文章

评论 (0)