使用LSTM(长短期记忆网络)模型预测股票价格的实例分析
一:LSTM与RNN的区别
LSTM(Long Short-Term Memory)是一种特殊的循环神经网络(RNN)架构。LSTM是为了解决传统RNN在处理长序列数据时遇到的梯度消失或梯度爆炸问题而设计的。
在传统的RNN中,信息通过隐藏状态在时间步之间传递,但由于权重的重复应用,随着时间的推移,梯度可能会迅速减小或增大,导致网络难以学习长期依赖关系。LSTM通过引入了一种称为“门”(gates)的机制来解决这个问题,这些门可以控制信息的流动,从而允许网络在长序列中有效地保持和传递信息。
LSTM的四个主要组成部分是:
1: 细胞状态(Cell State):一个流动的载体,它携带有关观察到的输入序列的信息。细胞状态可以跨越时间步传递信息。
2: 遗忘门(Forget Gate):决定哪些信息应该从细胞状态中丢弃。遗忘门会读取当前的输入和上一时间步的隐藏状态,并输出一个0到1之间的数值,表示保留信息的程度。
3: 输入门(Input Gate):决定哪些新信息将被存储到细胞状态中。输入门由两部分组成:一个sigmoid层决定哪些值将要更新,和一个tanh层创建一个新的候选值向量,它们将会被加入到状态中。
4: 输出门(Output Gate):决定下一个隐藏状态的值。它读取当前的细胞状态和输入,并通过一个sigmoid层和一个tanh层来计算输出值。
LSTM的这些门通过使用sigmoid激活函数来决定信息的保留或丢弃,而tanh激活函数则用来创建新的候选值或输出值。
由于其设计上的优势,LSTM能够捕捉长期依赖关系,因此在处理复杂序列数据时非常有效。
二:使用LSTM预测股票价格
一个典型的LSTM实例可以是股票价格预测。在这个例子中,我们可以使用LSTM模型来学习股票价格的时间序列数据,并尝试预测未来的价格走势。
为了实现这个实例,我们需要完成以下几个步骤:
- 数据收集:获取股票价格的历史数据。
- 数据预处理:
- 数据清洗:去除异常值。
- 数据归一化:使用MinMaxScaler将数据缩放到0到1之间。
- 构建LSTM模型:
- 设计网络结构:确定LSTM层的数量和每层的神经元数量。
- 添加全连接层:用于输出预测结果。
- 编译模型:选择优化器和损失函数。
- 训练模型:使用历史数据训练模型。
- 预测和评估:使用测试数据评估模型的性能。
接下来将演示一个使用Keras库中的LSTM(长短期记忆网络)模型进行股票价格预测的简单示例。
导入必要的库
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import LSTM, Dense
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
numpy
:用于数值计算。matplotlib.pyplot
:用于绘制图表。MinMaxScaler
:来自sklearn.preprocessing
,用于将数据缩放到指定的范围(这里是0到1)。Sequential
:来自keras.models
,用于创建神经网络模型。LSTM
和Dense
:来自keras.layers
,分别是LSTM层和全连接层。plt.rcParams
:设置matplotlib绘图参数,确保中文字体可以正确显示,并处理坐标轴的负号。
生成假设的股票价格数据集
prices = np.random.rand(100, 1).cumsum()
- 使用
numpy
生成一个100行1列的随机数组,并将其累加,模拟股票价格走势。
数据预处理
prices_reshaped = prices.reshape(-1, 1)
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_prices = scaler.fit_transform(prices_reshaped)
- 将一维的
prices
数组转换为二维,,因为MinMaxScaler
需要二维输入。例如,如果prices
是一个包含100个元素的一维数组,那么prices_reshaped
将会是一个形状为(100, 1)
的二维数组。 - 创建一个
MinMaxScaler
对象,并将其用于缩放数据到0和1之间。
创建数据集
X, Y = [], []
for i in range(60, len(scaled_prices)):
X.append(scaled_prices[i-60:i, 0])
Y.append(scaled_prices[i, 0])
X, Y = np.array(X), np.array(Y)
- 对于数据集中的每个点,使用过去60个时间点的数据作为输入
X
,并使用第61个时间点的数据作为输出Y
。 -
遍历归一化后的股票价格数据:
for i in range(60, len(scaled_prices)):
:这个循环从索引60开始,直到scaled_prices
数组的末尾。索引60意味着每个样本包含60个时间步长的数据。
-
构建输入数据X:
X.append(scaled_prices[i-60:i, 0])
:对于每个索引i
,从scaled_prices
中取出从i-60
到i-1
的60个数据点,这些数据点将作为模型的输入。这里[:, 0]
确保只选择一列数据,因为scaled_prices
是一个二维数组。
-
构建输出数据Y:
Y.append(scaled_prices[i, 0])
:对于每个索引i
,从scaled_prices
中取出索引为i
的数据点,这个数据点将作为模型的输出,即第61个时间步长的股票价格。
经过这个循环,X
将包含40个的60个时间步长的数据,而Y
将包含对应时间步长之后的股票价格。这样的数据结构非常适合用于训练时间序列预测模型LSTM,其中模型需要学习如何根据过去60个时间步长的数据来预测下一个时间步长的价格。
重构输入数据
X = np.reshape(X, (X.shape[0], X.shape[1], 1))
-
X
: 这是一个NumPy数组,包含了模型的输入数据。 -
np.reshape()
: NumPy中的函数,用于在不改变数据内容的情况下改变数组的形状。 -
(X.shape[0], X.shape[1], 1)
: 这是重塑操作的目标形状。X.shape[0]
: 表示X
数组的第一个维度40,即样本的数量。X.shape[1]
: 表示X
数组的第二个维度60,即每个样本的特征数量。1
: 表示为每个样本增加一个维度,使其成为三维数组。
在LSTM网络中,期望的输入数据格式通常是三维的,其形状为 [样本数量, 时间步长, 特征数量]
。在这个例子中,每个样本是一个时间序列,包含了过去60个时间点的数据,而每个时间点只有一个特征(股票价格)。通过这行代码,X
数组被重塑为以下形状:
[样本数量(40), 时间步长(60), 特征数量(1)]
这种形状是LSTM层能够正确处理的数据格式。
构建LSTM模型
model = Sequential()
model.add(LSTM(units=50, return_sequences=True, input_shape=(X.shape[1], 1)))
model.add(LSTM(units=50))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')
- 创建一个序贯模型。
- 添加两个LSTM层,第一个LSTM层返回序列,第二个不返回。
- 添加一个全连接层,输出一个值。
- 编译模型,使用Adam优化器和均方误差损失函数。
训练模型
model.fit(X, Y, epochs=1, batch_size=1, verbose=2)
- 使用数据
X
和Y
训练模型,设置一个周期,批量大小为1。 verbose=2
:输出每个epoch的进度以及每个epoch结束时的一些统计信息(如损失值)。
预测
predicted_prices = model.predict(X)
predicted_prices = scaler.inverse_transform(predicted_prices)
- 使用模型进行预测。
- 将预测结果从缩放后的数据转换回原始数据范围。
可视化结果
plt.figure(figsize=(10, 6))
plt.plot(prices, color='blue', label='实际价格')
plt.plot(np.arange(60, 100), predicted_prices, color='red', label='预测价格')
plt.title('股票价格预测')
plt.xlabel('时间')
plt.ylabel('价格')
plt.legend()
plt.show()
- 绘制实际价格和预测价格的图表,蓝色表示实际价格,红色表示预测价格。可视化图表如下:
可以看出建立的LSTM模型的预测效果较好。
三:每日股票行情数据
想要探索更多元化的数据分析视角,可以关注之前发布的相关内容。