问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

使用LSTM进行股票价格的时间序列预测

创作时间:
作者:
@小白创作中心

使用LSTM进行股票价格的时间序列预测

引用
CSDN
1.
https://m.blog.csdn.net/weixin_43729592/article/details/145108331

本文将详细介绍如何使用LSTM(长短期记忆网络)进行股票价格的时间序列预测。通过Python代码实现数据加载、预处理、模型定义、训练和结果可视化等多个步骤,帮助读者理解LSTM模型在实际问题中的应用。

1. 导入库并加载数据

import torch
import torch.nn as nn
import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from torch.utils.data import DataLoader, Dataset
from torch.utils.data import TensorDataset
import matplotlib.pyplot as plt
from tqdm import tqdm  # 导入tqdm库
import warnings  # 避免一些可以忽略的报错
warnings.filterwarnings('ignore')  # 过滤警告信息
plt.rcParams['font.sans-serif'] = ['SimHei']  # 正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号
# 加载数据
df = pd.read_csv("Microsoft_Stock.csv")
print(f"len(df): {len(df)}")    
df.head()
# 提取收盘价数据
Close = df['Close'].values
print(f"Close: {len(Close)}")        # Close:1511
# 绘制收盘价变化图
plt.plot([i for i in range(len(Close))], Close)
  • 导入必要的库,包括 PyTorch、Pandas、Numpy、sklearn、Matplotlib 等。
  • 读取 CSV 文件,提取相关列(如 Date、Open、High、Low、Close),并绘制收盘价变化图。

2. 数据预处理与归一化

# 选择相关的列,数据列名为:['Date', 'Open', 'High', 'Low', 'Close']
df = df[['Date', 'Open', 'High', 'Low', 'Close']]
# 转换日期为日期类型
df['Date'] = pd.to_datetime(df['Date'])
# 使用 MinMaxScaler 归一化数据
scaler = MinMaxScaler(feature_range=(-1, 1))
scaled_data = scaler.fit_transform(df[['Open', 'High', 'Low', 'Close']])
# 设置时间窗口 (Sequence Length)
seq_length = 3  # 过去3天的数据来预测当天的收盘价
# 数据划分函数
def split_data(data, seq_length):
    dataX = []
    datay = []
    for i in range(len(data)-seq_length):
        dataX.append(data[i:i+seq_length])
        datay.append(data[i+seq_length, 3])  # 收盘价是目标数据(归一化后对应第4列)
    dataX = np.array(dataX).reshape(len(dataX), seq_length, -1)
    datay = np.array(datay).reshape(len(dataX), -1)
    return np.array(dataX), np.array(datay)
# 创建数据集
dataX, datay = split_data(scaled_data, seq_length)
print(f"dataX.shape: {dataX.shape}, datay.shape: {datay.shape}")
  • 选择需要的列并将日期列转换为日期类型。
  • 使用 MinMaxScaler 对数据进行归一化,范围为 [-1, 1]。
  • 设置时间窗口为 3,表示使用过去 3 天的数据来预测当天的收盘价。
  • 使用 split_data 函数将数据划分为输入序列(dataX)和目标序列(datay)。

3. 训练集和测试集划分

# 数据集划分
X_train, X_test, y_train, y_test = train_test_split(dataX, datay, test_size=0.2, shuffle=False)
print(f"X_train.shape: {X_train.shape}, X_test.shape: {X_test.shape}")
# 转换为 PyTorch 张量
X_train = torch.tensor(X_train, dtype=torch.float32)
Y_train = torch.tensor(y_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
Y_test = torch.tensor(y_test, dtype=torch.float32)
# 打印训练集输入张量的形状
print('X_train: ', X_train.shape)
print('Y_train: ', Y_train.shape)
# 创建训练数据集和加载器
train_dataset = TensorDataset(X_train, Y_train)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=False)
# 创建测试数据集和加载器
test_dataset = TensorDataset(X_test, Y_test)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)
  • 使用 train_test_split 将数据集拆分为训练集和测试集。
  • 将 NumPy 数组转换为 PyTorch 张量。
  • 使用 TensorDataset 和 DataLoader 创建训练集和测试集的加载器。

4. 定义 LSTM 模型

# LSTM 模型定义
class LSTMModel(nn.Module):
    def __init__(self, input_size=4, hidden_size=64, output_size=1, num_layers=3):
        super(LSTMModel, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
        self.fc = nn.Linear(hidden_size, output_size)
    
    def forward(self, x):
        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)  # 初始化隐藏状态h0
        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)  # 初始化记忆状态c0
        out, _ = self.lstm(x, (h0, c0))  # 仅返回最后一个时间步的输出
        out = self.fc(out[:, -1, :])  # 取最后一个时间步的输出
        return out
    
# 初始化模型
model = LSTMModel(input_size=4, hidden_size=64, output_size=1, num_layers=1)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
  • 定义 LSTM 模型类,继承自 nn.Module。
  • init 中初始化 LSTM 层和全连接层。
  • 在 forward 方法中定义前向传播过程。
  • 初始化模型,并将模型移动到 GPU(如果可用)。

5. 训练模型

# 训练模型
criterion = nn.MSELoss()  # 使用均方误差损失函数
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
epochs = 100  # 设置训练轮数
train_losses = []
val_losses = []
for epoch in range(epochs):
    model.train()
    running_train_loss = 0.0
    
    for x_train, y_train in tqdm(train_loader, desc=f"Epoch {epoch+1}/{epochs} - Training", ncols=100):
        x_train, y_train = x_train.to(device), y_train.to(device)
        optimizer.zero_grad()  # 清空梯度
        y_train_pred = model(x_train)  # 模型预测
        loss = criterion(y_train_pred, y_train)  # 计算损失
        loss.backward()  # 反向传播
        optimizer.step()  # 更新权重
        
        running_train_loss += loss.item() * x_train.size(0)  # 累加训练损失
    
    epoch_train_loss = running_train_loss / len(train_loader.dataset)
    train_losses.append(epoch_train_loss)
    
    # 验证集评估
    model.eval()
    running_val_loss = 0.0
    with torch.no_grad():
        for x_test, y_test in test_loader:
            x_test, y_test = x_test.to(device), y_test.to(device)
            y_test_pred = model(x_test)  # 模型预测
            loss = criterion(y_test_pred, y_test)  # 计算损失
            running_val_loss += loss.item() * x_test.size(0)  # 累加验证损失
    
    epoch_val_loss = running_val_loss / len(test_loader.dataset)
    val_losses.append(epoch_val_loss)
    
    print(f"Epoch {epoch+1}/{epochs}, Train Loss: {epoch_train_loss:.4f}, Validation Loss: {epoch_val_loss:.4f}")
  • 设置损失函数为均方误差 (MSELoss),优化器为 Adam。
  • 在每个 epoch 中训练模型,并记录训练损失和验证损失。
  • 使用 tqdm 显示训练进度条。

6. 绘制损失曲线和预测结果

# 绘制训练和验证损失曲线
plt.figure(figsize=(8, 6))
plt.plot(range(1, epochs+1), train_losses, label='Train Loss', marker='o')
plt.plot(range(1, epochs+1), val_losses, label='Validation Loss', marker='s')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.title('Training and Validation Loss')
plt.legend()
# 获取模型预测值并反归一化
predictions = model(X_test).detach().numpy().reshape(-1, 1)
real_values = Y_test.detach().numpy().reshape(-1, 1)
# 将 predictions 和 real_values 转换为 (302, 4) 的数组,填充前三列为零
predictions = np
.column_stack([np.zeros((predictions.shape[0], 3)), predictions])  # 填充前三列为零
real_values = np.column_stack([np.zeros((real_values.shape[0], 3)), real_values])  # 填充前三列为零
# 反归一化
predictions = scaler.inverse_transform(predictions)[:, 3]  # 提取最后一列(即收盘价)
real_values = scaler.inverse_transform(real_values)[:, 3]  # 提取最后一列(即收盘价)
# 绘制预测结果与真实值
![](https://wy-static.wenxiaobai.com/chat-rag-image/2470810463944349839)
plt.figure(figsize=(12, 6))
plt.plot(real_values, label='真实值', color='blue')
plt.plot(predictions, label='预测值', color='red', linestyle='dashed')
plt.xlabel('时间步')
plt.ylabel('股票价格')
plt.title('LSTM 模型预测结果 vs 真实值')
plt.legend()
plt.show()
  • 绘制训练损失和验证损失的曲线。
  • 对模型的预测结果进行反归一化处理,确保恢复到原始的股票价格范围。
  • 绘制真实值与预测值的对比图。
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号