长短期记忆 (LSTM) 是一种特殊类型的循环神经网络 (RNN),它可以使用记忆细胞随时间保留重要信息。
LSTM 的这一特性使其成为学习相互依赖的序列的绝佳算法,可以帮助构建语言翻译、销售时间序列、聊天机器人、自动更正、下一个单词建议等解决方案。
在这个案例研究中,我将展示如何使用 LSTM 来学习股票价格的模式。 使用此模板,您将能够根据过去 10 天的价格预测明天的股票价格。
要提取任何股票的数据,我们可以使用名为“nsepy”的库
如果您想对任何其他股票执行此操作,只需使用该公司的股票市场代码,就像我在这里为 Infosys 使用“INFY”一样。
import pandas as pd
import numpy as np
# 从 numpy 数组中删除科学记数法
np.set_printoptions(suppress=True)
#安装 nsepy 库以获取股票价格
!pip install nsepy
############################################
# 使用 nsepy 库获取 Stock 数据
from nsepy import get_history
from datetime import datetime
startDate=datetime(2019, 1,1)
endDate=datetime(2020, 10, 5)
# 获取数据
StockData=get_history(symbol='INFY', start=startDate, end=endDate)
print(StockData.shape)
StockData.head()
# 创建一个日期列
StockData['TradeDate']=StockData.index
# 绘制股票价格
%matplotlib inline
StockData.plot(x='TradeDate', y='Close', kind='line', figsize=(20,6), rot=20)
LSTM 模型需要以 X Vs y 的形式输入数据。 其中 X 代表最近 10 天的价格,y 代表第 11 天的价格。
通过查看过去 2 年的大量此类示例,LSTM 将能够了解价格的变动。 因此,当我们通过价格的最后 10 天时,它将能够预测明天的股票收盘价。
由于 LSTM 是一种基于神经网络的算法,因此必须对数据进行标准化或规范化,以实现快速和更准确的拟合。
# 提取每天的收盘价
FullData=StockData[['Close']].values
print(FullData[0:5])
# 用于神经网络快速训练的特征缩放
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# 在标准化或规范化之间进行选择
#sc = StandardScaler()
sc=MinMaxScaler()
DataScaler = sc.fit(FullData)
X=DataScaler.transform(FullData)
#X=FullData
print('### After Normalization ###')
X[0:5]
# split into samples
X_samples = list()
y_samples = list()
NumerOfRows = len(X)
TimeSteps=10 # 第二天的价格预测是基于过去多少天的价格
# 遍历值以创建组合
for i in range(TimeSteps , NumerOfRows , 1):
x_sample = X[i-TimeSteps:i]
y_sample = X[i]
X_samples.append(x_sample)
y_samples.append(y_sample)
################################################
# 将输入重塑为 3D(样本数、时间步长、特征)
X_data=np.array(X_samples)
X_data=X_data.reshape(X_data.shape[0],X_data.shape[1], 1)
print('
#### Input Data shape ####')
print(X_data.shape)
# 我们不会将 y 重塑为 3D 数据,因为它应该只是一列
y_data=np.array(y_samples)
y_data=y_data.reshape(y_data.shape[0], 1)
print('
#### Output Data shape ####')
print(y_data.shape)
保留最后几天的数据以测试模型的学习情况,并休息以训练模型。
这里我选择最近 5 天作为测试。
# 选择测试数据记录的数量
TestingRecords=5
#将数据拆分为训练和测试
X_train=X_data[:-TestingRecords]
X_test=X_data[-TestingRecords:]
y_train=y_data[:-TestingRecords]
y_test=y_data[-TestingRecords:]
############################################
#打印训练和测试的形状
print('
#### Training Data shape ####')
print(X_train.shape)
print(y_train.shape)
print('
#### Testing Data shape ####')
print(X_test.shape)
print(y_test.shape)
打印一些示例输入和输出值,以帮助您直观地了解 LSTM 模型将如何学习价格。
您可以看到输入是最近 10 个价格的 3D 数组,输出是下一个价格的 1D 数组。
# 可视化发送到 LSTM 模型的输入和输出
for inp, out in zip(X_train[0:2], y_train[0:2]):
print(inp,'--', out)
查看使用 LSTM 函数而不是 Dense 来定义隐藏层。 输出层有一个神经元,因为我们预测的是第二天的价格,如果你想预测多天,那么改变输入数据和神经元等于预测的天数。
# 为 LSTM 定义输入形状
TimeSteps=X_train.shape[1]
TotalFeatures=X_train.shape[2]
print("Number of TimeSteps:", TimeSteps)
print("Number of Features:", TotalFeatures)
在下面的代码片段中,我使用了三个隐藏的 LSTM 层和一个输出层。 如果您的数据不准确,您可以选择更多层。 同样,您可以增加或减少隐藏层中的神经元数量。
请记住,您使用的神经元和层越多,模型变得越慢。 因为有更多的计算要做。
每层都有一些需要调整的超参数。
下面看看 LSTM 的一些重要超参数
#导入 Keras 库和包
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
#初始化RNN
regressor = Sequential()
# 添加第一个输入隐藏层和 LSTM 层
# return_sequences = True,表示每个时间步的输出要与隐藏的下一层共享
regressor.add(LSTM(units = 10, activation = 'relu', input_shape = (TimeSteps, TotalFeatures), return_sequences=True))
# 添加 Second Second 隐藏层和 LSTM 层
regressor.add(LSTM(units = 5, activation = 'relu', input_shape = (TimeSteps, TotalFeatures), return_sequences=True))
# 添加 Second Third 隐藏层和 LSTM 层
regressor.add(LSTM(units = 5, activation = 'relu', return_sequences=False ))
# 添加输出层
regressor.add(Dense(units = 1))
# 编译 RNN
regressor.compile(optimizer = 'adam', loss = 'mean_squared_error')
##################################################
import time
# 测量模型训练所花费的时间
StartTime=time.time()
# 将 RNN 拟合到训练集
regressor.fit(X_train, y_train, batch_size = 5, epochs = 100)
EndTime=time.time()
print("## Total Time Taken: ", round((EndTime-StartTime)/60), 'Minutes ##')
现在使用经过训练的模型,我们正在检查最近 5 天的预测价格是否接近实际价格。
注意预测的逆变换。 由于我们在模型训练之前对数据进行了归一化,因此对测试数据的预测也将被归一化,因此逆变换会将值恢复到原始规模。 那么只有我们必须计算百分比准确度。
# 对测试数据进行预测
predicted_Price = regressor.predict(X_test)
predicted_Price = DataScaler.inverse_transform(predicted_Price)
# 获取测试数据的原始价格值
orig=y_test
orig=DataScaler.inverse_transform(y_test)
# 预测的准确性
print('Accuracy:', 100 - (100*(abs(orig-predicted_Price)/orig)).mean())
#可视化结果
import matplotlib.pyplot as plt
plt.plot(predicted_Price, color = 'blue', label = 'Predicted Volume')
plt.plot(orig, color = 'lightblue', label = 'Original Volume')
plt.title('Stock Price Predictions')
plt.xlabel('Trading Date')
plt.xticks(range(TestingRecords), StockData.tail(TestingRecords)['TradeDate'])
plt.ylabel('Stock Price')
plt.legend()
fig=plt.gcf()
fig.set_figwidth(20)
fig.set_figheight(6)
plt.show()
绘制训练和测试数据以查看 LSTM 模型的拟合效果。
#对完整数据生成预测
TrainPredictions=DataScaler.inverse_transform(regressor.predict(X_train))
TestPredictions=DataScaler.inverse_transform(regressor.predict(X_test))
FullDataPredictions=np.append(TrainPredictions, TestPredictions)
FullDataOrig=FullData[TimeSteps:]
# 绘制完整数据
plt.plot(FullDataPredictions, color = 'blue', label = 'Predicted Price')
plt.plot(FullDataOrig , color = 'lightblue', label = 'Original Price')
plt.title('Stock Price Predictions')
plt.xlabel('Trading Date')
plt.ylabel('Stock Price')
plt.legend()
fig=plt.gcf()
fig.set_figwidth(20)
fig.set_figheight(8)
plt.show()
如果你想预测明天的价格,你所要做的就是将过去 10 天的价格以 3D 格式传递给训练中使用的模型。
下面的代码片段向您展示了如何手动获取最后 10 个价格并对下一个价格进行单一预测。
# 最近10天的价格
Last10Days=np.array([1002.15, 1009.9, 1007.5, 1019.75, 975.4,
1011.45, 1010.4, 1009,1008.25, 1017.65])
#就像我们训练模型一样归一化数据
Last10Days=DataScaler.transform(Last10Days.reshape(-1,1))
# 将数据的形状更改为 3D
# 选择 TimeSteps 为 10,因为我们已经将其用于训练
NumSamples=1
TimeSteps=10
NumFeatures=1
Last10Days=Last10Days.reshape(NumSamples,TimeSteps,NumFeatures)
#############################
# 对数据进行预测
predicted_Price = regressor.predict(Last10Days)
predicted_Price = DataScaler.inverse_transform(predicted_Price)
predicted_Price
在上面的代码片段中,我使用了截至上周五的股市实际价格!
因此,我们看到该模型预测(2020 年 10 月 5 日)Infosys 的下一个收盘价为 1023 ! 我查了一下,发现当天的收盘价是 1048 卢比! 这么小的努力还不错!
我们在上面建立的模型使用最近 10 天的价格并预测第二天的价格,因为我们已经用许多过去的相同粒度的示例训练了我们的模型,如下所示
最近 10 天的价格–> 第 11 天的价格
现在,如果我们想要预测接下来 5 天或接下来 20 天的价格,那么我们需要使用过去的类似示例来训练模型,如下所示
最近 10 天价格–> 未来 5 天价格
这也称为多步时间序列预测,我们在其中预测多个时间步长。
为此,需要对数据准备步骤和 LSTM 模型进行小幅修改。
但是,请记住,您预测得越远,您可能就越不准确,因为股票价格波动很大,没有人知道 10 天后会发生什么! 会传来什么样的消息? 这可能会影响这只股票的价格!
因此,建议预测尽可能少的时间步长,例如最多接下来 2 天或接下来 5 天。
我正在展示如何准备用于预测未来 5 天的数据。 同样的代码也可以轻松修改以预测接下来的 10 天或 20 天。
# 再次考虑我们上面提取的完整数据
# 打印最后 10 个值
print('Original Prices')
print(FullData[-10:])
print('###################')
# 打印我们在上面为最后一个模型创建的缩放数据的最后 10 个值
# 在这里,我将数据的形状更改为一维数组,因为对于多步数据准备,我们需要以这种方式进行 X 输入
X=X.reshape(X.shape[0],)
print('Scaled Prices')
print(X[-10:])
我修改了上一个模型的数据拆分逻辑,通过定义 FutureTimeSteps=5 来生成输入-> 输出对。 这决定了我们要根据过去 10 天预测未来 5 天的价格。
# 多步骤数据准备
# 拆分样本
X_samples = list()
y_samples = list()
NumerOfRows = len(X)
TimeSteps=10 # 未来几天的价格预测是基于过去多少天的价格
FutureTimeSteps=5 #您想预测未来多少天的价格
#遍历值以创建组合
for i in range(TimeSteps , NumerOfRows-FutureTimeSteps , 1):
x_sample = X[i-TimeSteps:i]
y_sample = X[i:i+FutureTimeSteps]
X_samples.append(x_sample)
y_samples.append(y_sample)
################################################
# 将输入重塑为 3D(样本、时间步长、特征)
X_data=np.array(X_samples)
X_data=X_data.reshape(X_data.shape[0],X_data.shape[1], 1)
print('### Input Data Shape ###')
print(X_data.shape)
# 我们不会将 y 重塑为 3D 数据,因为它应该只是一列
y_data=np.array(y_samples)
print('### Output Data Shape ###')
print(y_data.shape)
# 选择测试数据记录的数量
TestingRecords=5
# 将数据拆分为训练和测试
X_train=X_data[:-TestingRecords]
X_test=X_data[-TestingRecords:]
y_train=y_data[:-TestingRecords]
y_test=y_data[-TestingRecords:]
#############################################
# 打印训练和测试的形状
print('
#### Training Data shape ####')
print(X_train.shape)
print(y_train.shape)
print('
#### Testing Data shape ####')
print(X_test.shape)
print(y_test.shape)
打印一些输入和输出记录总是有助于理解 LSTM 模型中的过程。
您可以在此处看到输入是过去 10 天价格的 3D 数组,输出是接下来 5 天价格的数组。
# 可视化发送到 LSTM 模型的输入和输出
# 根据过去 10 天的价格,我们正在了解未来 5 天的价格
for inp, out in zip(X_train[0:2], y_train[0:2]):
print(inp)
print('====>')
print(out)
print('#'*20)
我使用的配置与上一个模型中使用的配置相同。 更改是在 Dense 层完成的。 现在密集层输出等于 FutureTimeSteps 的值的数量。 在本例中为 5,因为我们要预测接下来的 5 天。
如果您想要预测更多天数,您可以将其更改为 10 到 20,但您需要在运行此代码之前以相同的方式准备数据。
# Defining Input shapes for LSTM
TimeSteps=X_train.shape[1]
TotalFeatures=X_train.shape[2]
print("Number of TimeSteps:", TimeSteps)
print("Number of Features:", TotalFeatures)
# 导入 Keras 库和包
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
# 初始化RNN
regressor = Sequential()
# 添加第一个输入隐藏层和 LSTM 层
# return_sequences = True,表示每个时间步的输出要与隐藏的下一层共享
regressor.add(LSTM(units = 10, activation = 'relu', input_shape = (TimeSteps, TotalFeatures), return_sequences=True))
# 添加第二个隐藏层和 LSTM 层
regressor.add(LSTM(units = 5, activation = 'relu', input_shape = (TimeSteps, TotalFeatures), return_sequences=True))
#添加第三个隐藏层和 LSTM 层
regressor.add(LSTM(units = 5, activation = 'relu', return_sequences=False ))
# 添加输出层
# 注意密集层中的神经元数量现在是未来时间步数基于我们要预测的未来天数
regressor.add(Dense(units = FutureTimeSteps))
# 编译RNN
regressor.compile(optimizer = 'adam', loss = 'mean_squared_error')
###################################################################
import time
#测量模型训练所花费的时间
StartTime=time.time()
# 将 RNN 拟合到训练集
regressor.fit(X_train, y_train, batch_size = 5, epochs = 100)
EndTime=time.time()
print("############### Total Time Taken: ", round((EndTime-StartTime)/60), 'Minutes #############')
因为这是训练有素的多步模型来预测接下来的 5 天。 每个预测将生成 5 天的价格,我们可以将其与原始价格相匹配。
我们将一次比较它们一行。
# 对测试数据进行预测
predicted_Price = regressor.predict(X_test)
predicted_Price = DataScaler.inverse_transform(predicted_Price)
print('#### Predicted Prices ####')
print(predicted_Price)
# 获取测试数据的原始价格值
orig=y_test
orig=DataScaler.inverse_transform(y_test)
print('
#### Original Prices ####')
print(orig)
每行代表原始价格和预测价格。
我们将一次比较一行。 使用简单的 for 循环,将每行原始值与预测值进行比较
import matplotlib.pyplot as plt
for i in range(len(orig)):
Prediction=predicted_Price[i]
Original=orig[i]
# 可视化结果
plt.plot(Prediction, color = 'blue', label = 'Predicted Volume')
plt.plot(Original, color = 'lightblue', label = 'Original Volume')
plt.title('### Accuracy of the predictions:'+ str(100 - (100*(abs(Original-Prediction)/Original)).mean().round(2))+'% ###')
plt.xlabel('Trading Date')
startDateIndex=(FutureTimeSteps*TestingRecords)-FutureTimeSteps*(i+1)
endDateIndex=(FutureTimeSteps*TestingRecords)-FutureTimeSteps*(i+1) + FutureTimeSteps
TotalRows=StockData.shape[0]
plt.xticks(range(FutureTimeSteps), StockData.iloc[TotalRows-endDateIndex : TotalRows-(startDateIndex) , :]['TradeDate'])
plt.ylabel('Stock Price')
plt.legend()
fig=plt.gcf()
fig.set_figwidth(20)
fig.set_figheight(3)
plt.show()
如果你想预测未来 5 天的价格,你所要做的就是将过去 10 天的价格以 3D 格式传递给训练中使用的模型。
下面的代码片段向您展示了如何手动传递最后 10 个值以获得未来 5 天的价格预测。
# 对测试数据进行预测
Last10DaysPrices=array([1376.2, 1371.75,1387.15,1370.5 ,1344.95,
1312.05, 1316.65, 1339.45, 1339.7 ,1340.85])
# 将数据重塑为 (-1,1 ) 因为它是单个条目
Last10DaysPrices=Last10DaysPrices.reshape(-1, 1)
# 在训练模型的同一级别上缩放数据
X_test=DataScaler.transform(Last10DaysPrices)
NumberofSamples=1
TimeSteps=X_test.shape[0]
NumberofFeatures=X_test.shape[1]
# 将数据重塑为 3D 输入
X_test=X_test.reshape(NumberofSamples,TimeSteps,NumberofFeatures)
#生成未来 5 天的预测
Next5DaysPrice = regressor.predict(X_test)
# 以原始比例生成价格
Next5DaysPrice = DataScaler.inverse_transform(Next5DaysPrice)
Next5DaysPrice
这种预测只是短期的。 当您尝试预测多天(例如接下来的 30 天或 60 天)时,这会惨遭失败。 不是因为我们的 LSTM 模型不好,而是因为股市波动很大。 所以,不要仅仅把钱押在这个模型上! 做一些研究,然后使用这个模型作为分析的补充工具!
我希望您喜欢阅读这篇文章,它可以帮助您消除对 LSTM 模型的一些疑虑。 考虑与您的朋友分享这篇文章以帮助传播知识
页面更新:2024-03-05
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号