我需要查看stock_forcast.py文件的完整内容,了解其中LSTM模型的实现和使用情况,然后再对其进行解释。
filePath: c:\Users\czliu\Documents\python\stock_forcast.py
现在我已经查看了完整的stock_forcast.py文件,我将对其中的LSTM模型实现进行详细解释,包括模型定义、结构、参数、数据准备和训练过程等方面。# LSTM模型在股票预测程序中的实现分析
1. LSTM模型定义
在stock_forcast.py文件中,LSTM模型通过LSTMStockPredictor类实现:
class LSTMStockPredictor(nn.Module):
def __init__(self, input_size=1, hidden_size=64, num_layers=2, output_size=1, dropout=0.2):
super(LSTMStockPredictor, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
# LSTM层
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, dropout=dropout)
# 全连接层
self.fc = nn.Linear(hidden_size, output_size)
# Sigmoid激活函数,用于分类
self.sigmoid = nn.Sigmoid()
def forward(self, x):
# 初始化隐藏状态和细胞状态
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
# 前向传播LSTM
out, _ = self.lstm(x, (h0, c0))
# 取最后一个时间步的输出
out = self.fc(out[:, -1, :])
# 使用sigmoid激活函数得到概率
out = self.sigmoid(out)
return out
2. 模型结构详解
2.1 模型参数
input_size=1:输入特征维度,这里只使用股票收盘价作为输入hidden_size=64:LSTM隐藏层大小,决定模型的学习能力num_layers=2:LSTM堆叠层数,增加模型深度output_size=1:输出维度,这里输出一个概率值dropout=0.2: dropout比率,防止过拟合
2.2 网络结构
- LSTM层:使用PyTorch内置的
nn.LSTM实现,采用批量优先(batch_first=True)的输入格式 - 全连接层:将LSTM的输出映射到最终的预测值
- Sigmoid激活函数:将输出转换为0-1之间的概率值,表示上涨的可能性
2.3 前向传播过程
- 初始化隐藏状态(
h0)和细胞状态(c0)为全零张量 - 将输入数据通过LSTM层,得到输出序列和最终的隐藏状态
- 只取LSTM输出序列的最后一个时间步的输出,因为我们只需要预测下一天的趋势
- 将LSTM的输出通过全连接层和Sigmoid激活函数,得到最终的预测概率
3. 数据准备与预处理
模型使用prepare_data_for_lstm函数处理数据:
def prepare_data_for_lstm(data, look_back=60, test_size=0.2):
# 使用收盘价作为特征
close_prices = data['Close'].values.reshape(-1, 1)
# 数据归一化
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(close_prices)
# 创建数据集
X, y = [], []
for i in range(len(scaled_data) - look_back):
X.append(scaled_data[i:(i + look_back), 0])
# 预测下一天是涨(1)还是跌(0)
y.append(1 if scaled_data[i + look_back, 0] > scaled_data[i + look_back - 1, 0] else 0)
X, y = np.array(X), np.array(y)
# 转换为LSTM需要的形状 [样本数, 时间步, 特征数]
X = np.reshape(X, (X.shape[0], X.shape[1], 1))
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, shuffle=False)
# 转换为PyTorch张量
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.float32).unsqueeze(1)
y_test = torch.tensor(y_test, dtype=torch.float32).unsqueeze(1)
return X_train, X_test, y_train, y_test, scaler, len(X_train)
关键处理步骤:
- 使用收盘价作为特征:从股票数据中提取收盘价
- 数据归一化:使用
MinMaxScaler将数据缩放到0-1之间,提高模型训练稳定性 - 构建时间序列数据集:
- 使用
look_back=60个连续的收盘价作为输入 - 预测第61天的涨跌情况(1表示涨,0表示跌)
- 调整数据形状:转换为LSTM需要的三维格式 [样本数, 时间步, 特征数]
- 划分训练集和测试集:按时间顺序划分,保持时间序列特性
- 转换为PyTorch张量:适配PyTorch框架的输入格式
4. 模型训练过程
模型训练通过train_lstm_model函数实现:
def train_lstm_model(model, X_train, y_train, X_test, y_test, epochs=100, batch_size=32, learning_rate=0.001):
# 定义损失函数和优化器
criterion = nn.BCELoss() # 二元交叉熵损失
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
# 创建DataLoader
train_dataset = TensorDataset(X_train, y_train)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
# 训练模型
train_losses = []
test_losses = []
for epoch in range(epochs):
model.train()
train_loss = 0.0
for batch_X, batch_y in train_loader:
# 前向传播
outputs = model(batch_X)
loss = criterion(outputs, batch_y)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss += loss.item()
# 计算平均训练损失
train_loss /= len(train_loader)
train_losses.append(train_loss)
# 在测试集上评估
model.eval()
with torch.no_grad():
test_outputs = model(X_test)
test_loss = criterion(test_outputs, y_test).item()
test_losses.append(test_loss)
# 打印训练进度
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch+1}/{epochs}], Train Loss: {train_loss:.4f}, Test Loss: {test_loss:.4f}')
return model, train_losses, test_losses
训练关键设置:
- 损失函数:使用二元交叉熵损失(
BCELoss),适合二分类问题 - 优化器:使用Adam优化器,学习率
0.001 - 批次训练:使用
batch_size=32进行小批量训练 - 训练轮次:训练
100个epoch - 训练监控:每10个epoch打印一次训练损失和测试损失
5. 模型预测与评估
5.1 预测过程
def predict_stock_trend(model, X_test, y_test):
model.eval()
with torch.no_grad():
predictions = model(X_test)
# 转换为0/1分类
predicted_classes = (predictions > 0.5).float()
# 计算准确率
accuracy = (predicted_classes == y_test).float().mean()
print(f'模型准确率: {accuracy:.4f}')
return predictions, predicted_classes, accuracy
预测步骤:
- 将模型设置为评估模式(
model.eval()) - 关闭梯度计算(
with torch.no_grad())以提高效率 - 使用模型进行预测,得到每个样本的上涨概率
- 将概率转换为0/1分类结果(概率>0.5为涨,否则为跌)
- 计算模型在测试集上的准确率
5.2 结果可视化
程序提供了plot_prediction_results函数,用于可视化预测结果,包括:
- 股票实际收盘价和测试集分割点
- 模型预测的涨跌趋势
6. LSTM模型的应用特点
- 时间序列建模:LSTM特别适合处理时间序列数据,能够捕捉股票价格的时序特征
- 长期依赖捕获:通过门控机制,LSTM能够记住长期的价格模式
- 二分类任务:这里LSTM被用于预测股票涨跌的二分类任务,而非直接预测价格
- 滑动窗口输入:使用60天的历史数据预测下一天的趋势,符合股票分析的常用方法
7. 程序中的LSTM工作流程
- 数据获取:从akshare获取股票历史数据
- 数据预处理:计算技术指标,准备LSTM输入数据
- 模型初始化:创建LSTM模型实例
- 模型训练:使用训练集训练LSTM模型
- 模型评估:在测试集上评估模型性能
- 结果可视化:绘制价格走势图和预测结果图
这个LSTM模型实现了一个基础的股票趋势预测系统,通过深度学习的方法尝试捕捉股票价格的短期波动模式。
开始预测 中国海油 600938
请输入股票代码(如 000001 或 600000):600938
开始训练LSTM模型…
Epoch [10/100], Train Loss: 0.6936, Test Loss: 0.6958
Epoch [20/100], Train Loss: 0.6930, Test Loss: 0.6958
Epoch [30/100], Train Loss: 0.6936, Test Loss: 0.6907
Epoch [40/100], Train Loss: 0.6924, Test Loss: 0.6894
Epoch [50/100], Train Loss: 0.6922, Test Loss: 0.6881
Epoch [60/100], Train Loss: 0.6915, Test Loss: 0.6836
Epoch [70/100], Train Loss: 0.6917, Test Loss: 0.6800
Epoch [80/100], Train Loss: 0.6924, Test Loss: 0.6816
Epoch [90/100], Train Loss: 0.6882, Test Loss: 0.7051
Epoch [100/100], Train Loss: 0.6904, Test Loss: 0.6809
模型准确率: 0.5676
完整代码:
# 程序用途及神经网络预测结果解释
## 一、程序主要用途
该Python程序是一个综合的股票分析工具,主要功能包括:
1. **股票数据获取**:使用akshare库从公开数据源获取A股股票的历史交易数据(默认获取近一年的日线数据)。
2. **技术指标计算**:
- 计算指数移动平均线(EMA,默认20日)
- 计算价格波动标准差(STD,默认20日)
3. **技术分析可视化**:
- 绘制股票收盘价与EMA指标对比图
- 绘制股票价格波动性(STD)走势图
4. **LSTM神经网络预测**:
- 使用长短期记忆网络(LSTM)预测股票次日涨跌趋势
- 训练模型并评估预测准确率
- 可视化预测结果与实际价格走势对比
## 二、神经网络预测结果解释
### 1. 训练过程指标
- **Epoch**:训练轮次,程序默认训练100轮
- **Train Loss**:训练集损失,反映模型在训练数据上的拟合程度
- **Test Loss**:测试集损失,反映模型在未见过数据上的泛化能力
从您提供的训练日志看:
```
Epoch [90/100], Train Loss: 0.6398, Test Loss: 0.8248
Epoch [100/100], Train Loss: 0.6300, Test Loss: 0.9487
```
训练损失逐渐下降,但测试损失在后期有所上升,说明模型可能出现了一定程度的过拟合(在训练数据上表现好,但对新数据预测能力下降)。
### 2. 模型准确率
```
模型准确率: 0.5135
```
准确率约为51.35%,表示模型预测正确的比例。这个准确率略高于随机猜测(50%),说明模型有一定的预测能力,但效果并不理想。
### 3. 预测结果可视化
- **上半部分图表**:显示股票实际收盘价走势,并标注测试集开始位置
- **下半部分图表**:显示模型对测试集的预测结果(0表示跌,1表示涨)
### 4. 模型局限性与改进方向
- **数据量限制**:仅使用了近一年的日线数据,可考虑增加更长时间周期的数据
- **特征单一**:目前仅使用收盘价作为特征,可加入成交量、换手率等更多指标
- **模型结构**:可尝试调整LSTM层数、隐藏单元数量或添加更多网络层
- **训练参数**:可调整学习率、批量大小、训练轮次等参数
- **过拟合问题**:可添加正则化技术(如L2正则化、Dropout)或使用早停法
## 三、使用建议
1. **数据选择**:建议选择交易活跃、数据质量好的股票进行分析
2. **参数调整**:根据不同股票特性调整技术指标参数(如EMA窗口大小)和LSTM模型参数
3. **结果解读**:股票价格受多种因素影响,模型预测仅供参考,不应作为投资决策的唯一依据
4. **持续优化**:可根据实际预测效果持续调整模型结构和参数
该程序提供了一个完整的股票分析框架,您可以在此基础上根据自己的需求进一步扩展功能或优化模型。
```{python}
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 设置中文显示
plt.rcParams["font.family"] = ["SimHei", "Microsoft YaHei", "SimSun", "KaiTi", "FangSong"]
plt.rcParams["axes.unicode_minus"] = False
import akshare as ak
from datetime import datetime, timedelta
import torch
import torch.nn as nn
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from torch.utils.data import DataLoader, TensorDataset
def fetch_stock_data(symbol, period='1y'):
"""获取股票数据"""
end_date = datetime.now().strftime('%Y%m%d')
start_date = (datetime.now() - timedelta(days=365)).strftime('%Y%m%d')
# 处理股票代码格式,确保符合akshare要求
if not symbol.startswith(('sh', 'sz')):
if symbol.startswith(('6', '9')):
symbol = f"sh{symbol}"
else:
symbol = f"sz{symbol}"
# 使用更稳定的stock_zh_a_hist函数获取股票日线数据
data = ak.stock_zh_a_hist(symbol=symbol[2:], # 只传股票代码部分,不含sh/sz
period="daily",
start_date=start_date,
end_date=end_date,
adjust="qfq") # 使用前复权价格
# 检查数据获取是否成功
if data.empty:
print(f"获取股票{symbol}数据失败,请检查股票代码和网络连接")
return None
# 先转换日期格式
if '日期' in data.columns:
data['日期'] = pd.to_datetime(data['日期'])
# 设置日期为索引
data.set_index('日期', inplace=True)
# 重命名收盘价列
if '收盘' in data.columns:
data = data.rename(columns={'收盘': 'Close'})
else:
print("数据格式异常,无法处理")
return None
return data
def calculate_ema(data, window=20):
"""计算指数移动平均线 EMA"""
ema = data['Close'].ewm(span=window, adjust=False).mean()
return ema
def calculate_std(data, window=20):
"""计算标准差 STD"""
std = data['Close'].rolling(window=window).std()
return std
def plot_analysis(data, ema, std, symbol):
"""绘制图表分析结果"""
plt.figure(figsize=(14, 8))
plt.subplot(2, 1, 1)
plt.plot(data['Close'], label='收盘价', color='blue')
plt.plot(ema, label='EMA(20)', color='orange')
plt.title(f'{symbol} 股票价格与EMA分析')
plt.legend()
plt.subplot(2, 1, 2)
plt.plot(std, label='STD(20)', color='red')
plt.title(f'{symbol} 股票价格波动性(STD)分析')
plt.legend()
plt.tight_layout()
plt.show()
# LSTM模型定义
class LSTMStockPredictor(nn.Module):
def __init__(self, input_size=1, hidden_size=64, num_layers=2, output_size=1, dropout=0.2):
super(LSTMStockPredictor, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
# LSTM层
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, dropout=dropout)
# 全连接层
self.fc = nn.Linear(hidden_size, output_size)
# Sigmoid激活函数,用于分类
self.sigmoid = nn.Sigmoid()
def forward(self, x):
# 初始化隐藏状态和细胞状态
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
# 前向传播LSTM
out, _ = self.lstm(x, (h0, c0))
# 取最后一个时间步的输出
out = self.fc(out[:, -1, :])
# 使用sigmoid激活函数得到概率
out = self.sigmoid(out)
return out
def prepare_data_for_lstm(data, look_back=60, test_size=0.2):
"""准备LSTM模型的数据"""
# 使用收盘价作为特征
close_prices = data['Close'].values.reshape(-1, 1)
# 数据归一化
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(close_prices)
# 创建数据集
X, y = [], []
for i in range(len(scaled_data) - look_back):
X.append(scaled_data[i:(i + look_back), 0])
# 预测下一天是涨(1)还是跌(0)
y.append(1 if scaled_data[i + look_back, 0] > scaled_data[i + look_back - 1, 0] else 0)
X, y = np.array(X), np.array(y)
# 转换为LSTM需要的形状 [样本数, 时间步, 特征数]
X = np.reshape(X, (X.shape[0], X.shape[1], 1))
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, shuffle=False)
# 转换为PyTorch张量
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.float32).unsqueeze(1)
y_test = torch.tensor(y_test, dtype=torch.float32).unsqueeze(1)
return X_train, X_test, y_train, y_test, scaler, len(X_train)
def train_lstm_model(model, X_train, y_train, X_test, y_test, epochs=100, batch_size=32, learning_rate=0.001):
"""训练LSTM模型"""
# 定义损失函数和优化器
criterion = nn.BCELoss() # 二元交叉熵损失
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
# 创建DataLoader
train_dataset = TensorDataset(X_train, y_train)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
# 训练模型
train_losses = []
test_losses = []
for epoch in range(epochs):
model.train()
train_loss = 0.0
for batch_X, batch_y in train_loader:
# 前向传播
outputs = model(batch_X)
loss = criterion(outputs, batch_y)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss += loss.item()
# 计算平均训练损失
train_loss /= len(train_loader)
train_losses.append(train_loss)
# 在测试集上评估
model.eval()
with torch.no_grad():
test_outputs = model(X_test)
test_loss = criterion(test_outputs, y_test).item()
test_losses.append(test_loss)
# 打印训练进度
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch+1}/{epochs}], Train Loss: {train_loss:.4f}, Test Loss: {test_loss:.4f}')
return model, train_losses, test_losses
def predict_stock_trend(model, X_test, y_test):
"""使用训练好的模型预测股票趋势"""
model.eval()
with torch.no_grad():
predictions = model(X_test)
# 转换为0/1分类
predicted_classes = (predictions > 0.5).float()
# 计算准确率
accuracy = (predicted_classes == y_test).float().mean()
print(f'模型准确率: {accuracy:.4f}')
return predictions, predicted_classes, accuracy
def plot_prediction_results(data, predicted_classes, look_back, n_train):
"""绘制预测结果"""
plt.figure(figsize=(14, 8))
# 获取测试集对应的原始数据
test_start_index = n_train + look_back
test_data = data.iloc[test_start_index:]
# 创建预测结果的DataFrame
prediction_df = pd.DataFrame(index=test_data.index)
prediction_df['Actual'] = data['Close'].iloc[test_start_index:]
prediction_df['Predicted_Trend'] = predicted_classes.numpy().flatten()
# 绘制收盘价和预测趋势
plt.subplot(2, 1, 1)
plt.plot(data['Close'], label='实际收盘价', color='blue')
if not test_data.empty:
plt.axvline(x=test_data.index[0], color='red', linestyle='--', label='测试集开始')
plt.title('股票价格与测试集分割')
plt.legend()
# 绘制预测趋势
plt.subplot(2, 1, 2)
if not test_data.empty:
plt.plot(test_data.index, prediction_df['Predicted_Trend'], label='预测涨跌', color='green', marker='o', linestyle='')
plt.title('LSTM模型预测股票涨跌')
plt.yticks([0, 1], ['跌', '涨'])
plt.legend()
plt.tight_layout()
plt.show()
def main():
symbol = input("请输入股票代码(如 000001 或 600000):")
data = fetch_stock_data(symbol)
# 检查数据获取是否成功
if data is not None:
# 计算技术指标
ema = calculate_ema(data)
std = calculate_std(data)
# 绘制技术分析图表
plot_analysis(data, ema, std, symbol)
# 准备LSTM模型数据
look_back = 60
test_size = 0.2
X_train, X_test, y_train, y_test, scaler, n_train = prepare_data_for_lstm(data, look_back, test_size)
# 初始化模型
model = LSTMStockPredictor(input_size=1, hidden_size=64, num_layers=2, output_size=1, dropout=0.2)
# 训练模型
print("开始训练LSTM模型...")
model, train_losses, test_losses = train_lstm_model(model, X_train, y_train, X_test, y_test, epochs=100, batch_size=32, learning_rate=0.001)
# 预测股票趋势
predictions, predicted_classes, accuracy = predict_stock_trend(model, X_test, y_test)
# 绘制预测结果
plot_prediction_results(data, predicted_classes, look_back, n_train)
# 绘制损失曲线
plt.figure(figsize=(10, 6))
plt.plot(range(1, len(train_losses) + 1), train_losses, label='训练损失')
plt.plot(range(1, len(test_losses) + 1), test_losses, label='测试损失')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('LSTM模型训练损失曲线')
plt.legend()
plt.show()
if __name__ == '__main__':
main()
```
# 问豆包:Python股票分析,akshare获取数据,可视化长度傲气记忆网络(LSTM),神经模型采用pytorch。预测股票涨跌
