LSTM股价预测实战:数据预处理、模型训练与评估全流程解析

发布时间:2026/10/5 11:16:25
LSTM股价预测实战:数据预处理、模型训练与评估全流程解析 简介这是一份用于学习LSTM并开展股价预测实践的开源代码包适合初学者入门循环神经网络时序建模也适合有一定基础者快速复现预测流程。包内文件总数153个以89个Python脚本为主体覆盖数据读取、归一化、窗口序列构建、模型训练与评估28个CSV文件提供历史行情及空气质量等多组示例数据便于替换测试另有若干TXT说明、XML配置、checkpoint权重文件及H5模型文件支持断点续训和直接加载模型。压缩包整体仅5.49MB结构清晰可直接在本地或服务器环境运行。目前已有90人学习下载。通过阅读源码和运行代码可理解LSTM的输入门、输出门、遗忘门及单元状态机制并掌握从特征工程、指标计算到Keras/TensorFlow模型搭建的完整股价预测实现思路适合作为毕设或项目起步模板。1. 从 LSTM 到股价预测这份开源代码到底解决什么问题很多刚接触 LSTM 的人卡在同一个地方理论看了一堆知道它有遗忘门、输入门、输出门知道它能缓解梯度消失但一到自己动手就懵了——数据怎么喂进去时间步长选多少归一化是不是必须的预测出来的结果怎么还原成真实价格这份基于 Keras 的可执行代码把「数据预处理 → 滑窗构样 → LSTM 建模 → 训练保存 → 预测还原」整条链路串通了仓库自带 CSV 数据clone 下来改下文件路径就能跑出第一个预测结果。值得说明的是仓库里自带的是空气污染时序数据但代码路径和股价预测完全一致——股价和污染浓度本质上都是多变量时间序列你要做的只是把 CSV 换成股票历史行情。我拆这份代码时重点验证了三件事数据管道是否闭环、LSTM 层参数是否可调、checkpoint 是否真的能恢复训练。这篇笔记会把每一步的命令、参数和踩坑都摊开讲。2. 数据预处理与滑窗构样归一化、时间步长与训练集划分2.1 MinMaxScaler 归一化为什么股价预测必须先做这一步股价原始数据的量纲差异很大收盘价可能是一百多成交量是几十万技术指标又是零点几。LSTM 内部用的是 tanh 和 sigmoid 激活函数输入尺度不一致会直接导致梯度更新不稳定。这份代码里用的是 MinMaxScaler把所有特征压缩到 [0,1] 区间这是时序预测最常见也最稳妥的做法。from sklearn.preprocessing import MinMaxScaler import pandas as pd df pd.read_csv(pollution.csv, encodingutf-8) # 假设取收盘价、成交量、最高价、最低价作为特征 features [close, volume, high, low] data df[features].values scaler MinMaxScaler(feature_range(0, 1)) scaled scaler.fit_transform(data)这里有一个关键细节fit_transform只能用在训练集上验证集和测试集必须用同一个 scaler 的transform方法否则就造成了数据泄漏。我在拆代码时特意检查了 utils.py 里的实现确认它是先划分 train/test 再分别缩放这个顺序不能反。2.2 滑窗生成监督学习样本lookback 参数怎么选LSTM 不能直接吃一整个时间序列需要把数据切成「过去 N 步 → 未来 1 步」的监督学习样本。这个 N 就是 lookback也就是时间步长。代码里的核心函数会遍历整个时间轴每 N 条数据生成一个样本第 N1 条作为标签。def create_samples(data, lookback1): X, y [], [] for i in range(len(data) - lookback - 1): X.append(data[i:(i lookback), :]) y.append(data[i lookback, 3]) # 取 close 列作为预测目标 return np.array(X), np.array(y) X, y create_samples(scaled, lookback5) # 划分训练集与测试集 train_size int(len(X) * 0.8) X_train, X_test X[:train_size], X[train_size:] y_train, y_test y[:train_size], y[train_size:]这段代码里 lookback5 表示用过去 5 天的特征预测下一天。参数怎么调取决于数据频率日线数据我一般取 5 到 20分钟线可以取 30 到 60。但要注意lookback 太大反而会把远古噪音带进模型太小又学不到趋势这个后面第五节展开讲。2.3 数据集划分的边界条件时序数据不能随机打乱分类任务里 train_test_split 默认会 shuffle但时序数据绝对不能 shuffle。股价预测的训练顺序就是时间顺序打乱之后模型学的是「片段间的伪规律」而不是时间依赖。这份代码用的是按比例切片也就是前 80% 训练、后 20% 测试这种做法对时间序列来说才是对的。划分比例方面我自己的习惯是数据量大超过一万条用 90/10数据量小用 75/25。代码里默认 0.8 也可以但如果你发现测试集上表现异常好先回头确认是不是当前日期数据被混进了训练集。3. LSTM 模型构建与训练配置从网络结构到 checkpoint 恢复3.1 网络结构单层 LSTM 还是堆叠 LSTM神经元数量怎么定这份代码的模型是用 Keras Sequential API 搭的核心结构是 LSTM 层加 Dense 输出层。对于单变量预测一个 LSTM 层通常就够但如果特征维度多、序列长堆叠两层能学到更高层级的抽象特征。问题在于层数越多训练越慢过拟合风险也越高。from keras.models import Sequential from keras.layers import LSTM, Dense, Dropout model Sequential() model.add(LSTM(units128, return_sequencesTrue, input_shape(lookback, X_train.shape[2]))) model.add(Dropout(0.2)) model.add(LSTM(units64, return_sequencesFalse)) model.add(Dropout(0.2)) model.add(Dense(units1)) model.compile(optimizeradam, lossmse, metrics[mae])神经元数量 128 和 64 不是拍脑袋定的。经验规则是第一层取特征维度乘以 8 到 16如果特征只有 4 列128 就够用了。return_sequencesTrue表示这一层输出完整序列给下一层 LSTM最后一层 LSTM 才设为 False只输出最后一个时间步的结果。这里的 Dropout 放在 LSTM 层之间随机丢弃 20% 的神经元连接是防过拟合的标准手段。3.2 训练参数epochs、batch_size 与早停策略训练过程的几个参数直接决定模型能不能收敛。代码里设置 epochs100但实际训练时我发现 100 轮对这份数据偏大——大约跑到 40 到 50 轮 loss 就不再明显下降。解决办法是加 EarlyStopping让它自动在验证集 loss 不再改善时停下来。from keras.callbacks import EarlyStopping, ModelCheckpoint early_stop EarlyStopping(monitorval_loss, patience5, restore_best_weightsTrue) checkpoint ModelCheckpoint( filepathcheckpoint/lstm_model.h5, monitorval_loss, save_best_onlyTrue, verbose1 ) history model.fit( X_train, y_train, epochs100, batch_size64, validation_split0.1, callbacks[early_stop, checkpoint], verbose1 )batch_size64表示每 64 条样本更新一次梯度显存或内存不够时降到 32 或 16。validation_split0.1会在训练集尾部自动切出 10% 做验证注意这里也是按顺序切不会打乱。checkpoint 的save_best_onlyTrue保证磁盘上永远是最小 val_loss 的模型这个文件就是后面预测阶段要加载的权重。3.3 checkpoint 的真正用途断点续训与最佳权重找回很多人不知道 checkpoint 不只是「防止训练白跑」它最大的价值是帮你找回验证集上最好的状态。LSTM 训练过程中 loss 是震荡下行的最后几轮可能反而过拟合了。有了 checkpoint你永远不需要手动记「跑到第几轮最好」训练结束后直接加载这个 h5 文件就行。from keras.models import load_model model load_model(checkpoint/lstm_model.h5)加载之后建议用model.summary()确认结构完整再看一眼model.get_weights()第一个数组的 shape确认权重确实被更新过。如果 checkpoint 文件只有几 KB那大概率是训练没跑到第一次保存就中断了要检查verbose1输出里的保存记录。4. 评估与预测RMSE 怎么算结果怎么还原成真实股价4.1 评价指标RMSE 和 MAE 各自能看到什么问题代码在训练时监控的 mae 是平均绝对误差单位是归一化后的数值。要判断模型到底准不准必须在反归一化之后计算 RMSE。这里有个容易翻车的点如果你直接拿归一化后的误差说「误差只有 0.03」那是骗自己真实股价误差要乘回去才算数。import numpy as np from sklearn.metrics import mean_squared_error, mean_absolute_error # y_test_inv 是反归一化后的真实值pred_inv 是反归一化后的预测值 rmse np.sqrt(mean_squared_error(y_test_inv, pred_inv)) mae mean_absolute_error(y_test_inv, pred_inv) print(fRMSE: {rmse:.2f}, MAE: {mae:.2f})RMSE 对大误差更敏感——如果模型偶尔预测偏差很大RMSE 会比 MAE 高不少。当你看到 RMSE 远大于 MAE 时说明存在明显的极端预测错误常见的元凶是测试集里有大涨大跌的交易日而模型没见过这种波动幅度。4.2 单点预测 vs. 多步预测为什么直接预测明天反而更靠谱这份代码默认做的是「单步预测」也就是用过去 N 天预测下一天。训练时每个样本的标签都是真实的下一日数据所以拟合的是真实的输入输出关系。但很多人拿到代码后第一反应是拿预测值递归地继续预测做多步展望这个做法在长序列上会误差累积越往后越飘。def predict_next_days(model, last_sequence, scaler, days5): results [] current last_sequence.copy() for _ in range(days): next_val model.predict(current[np.newaxis, :, :], verbose0) results.append(next_val[0, 0]) # 用预测值滚动更新窗口 current np.roll(current, -1, axis0) current[-1, 3] next_val[0, 0] return scaler.inverse_transform(np.array(results).reshape(-1, 1))这段代码展示的是自回归式多步预测。np.roll把窗口整体往前推一格再用刚预测出的值填充最后一行的 close 列。这种做法的好处是能画出未来五天的预测曲线坏处是误差会累积——第一天预测偏了 2%第二天可能就偏 4%。所以你要是做短线策略最好用单步预测配合每日滚动更新而不是一次把未来十天全猜完。5. 文件结构与常见问题排查五个高频踩坑记录5.1 仓库文件清单与职责划分拆这份代码时我建议按入口文件往下追而不是一上来读源码。整个仓库的功能分配很清晰文件职责需要关注的函数/变量content.py数据加载与特征选取load_data()决定读哪些列utils.py归一化、滑窗、可视化create_samples()、plot_results()model.pyLSTM 网络定义与训练build_model()、epochs、batch_sizepredict.py加载 checkpoint 并预测模型路径、预测步数pollution.csv/air_pollution_new.csv演示数据时间列格式、缺失值标记checkpoint/训练中保存的最佳模型h5 文件预测阶段依赖logging.conf训练日志输出格式控制台和文件的日志级别这个文件结构和我之前拆过的项目几乎一致content.py 管输入utils.py 管管道model.py 管训练predict.py 管推理日志单独走 logging.conf划分得很干净。你要替换成自己的数据只需要动 content.py 的列选择和 utils.py 的特征矩阵顺序。5.2 踩坑记录现象、原因与解决踩坑一预测曲线是平的几乎没有波动现象模型训练完预测结果画出来近似一条直线。原因这是归一化和滑窗配合出的问题。如果滑窗窗口太长每个样本都包含大量历史信息模型学到的最优策略就是输出接近历史均值的值。另一个常见原因是学习率太大loss 在震荡中没有真正收敛。解决把 lookback 从 20 降到 5 或 8同时把 EarlyStopping 的 patience 从 5 调到 10让训练多跑几轮。如果还是平的检查 y 列是否选错——如果标签列被归一化成均值为 0 的序列模型学到的基本就是均值回归。踩坑二checkpoint 文件加载后预测报维度错误现象load_model成功但model.predict报Input 0 is incompatible with layer之类的 shape 错误。原因训练时输入的 shape 是(lookback, features)加载后忘了确认input_shape。常见于改过 lookback 之后又去加载旧模型。解决别用命名猜直接打印model.input.shape和X_test.shape对比。我在拆这份代码时踩了同样的坑——第一次改 lookback10 后忘了删旧的 h5 文件加载的还是 lookback5 的模型shape 对不上。踩坑三归一化泄漏导致测试集效果虚高现象测试集 RMSE 只有训练集的一半好得不真实。原因用了全量数据的fit_transform再划分训练测试集。测试集的缩放范围被训练数据泄露给了模型预测自然「准确」。解决严格保证同一 scaler 只 fit 训练集测试集只 transform。建议把这一条写成代码注释放在utils.py顶部防止后续修改代码的人破坏这个顺序。踩坑四日志文件无限增长现象跑完训练后发现 logging.conf 指定了日志文件但每次运行都往同一个文件追加几天下来日志有几百万行。原因logging.conf 里 FileHandler 默认是 append 模式没有按日期轮转。解决改配置文件里的 handler加一个whenmidnight, interval1, backupCount7的 TimedRotatingFileHandler 配置保留七天的日志就够了。这个不治标不治本顺手把levelINFO排队输出改成生产级别能省不少磁盘。踩坑五训练时间过长但 loss 不降现象epochs 跑了一百轮val_loss 卡在某个数值上下抖动耗了几个小时。原因LSTM 对学习率敏感Adam 默认 lr0.001 对这份数据可能偏大或偏小。还有可能是数据量太小加 epochs 没有意义。解决从 lr0.001 往下调一档到 0.0005观察前 10 轮的趋势。如果 loss 在第一个 epoch 就跌到接近 0那大概率是数据泄漏不是模型变聪明了。6. 让预测结果真正能用多特征输入与滚动验证的落地技巧如果你只想复现这份代码前五章已经够了。但如果想让预测进入实盘回测有一个技巧我觉得特别值钱——把预测做成一站式滚动验证而不是一次性跑完就结束。我一般会把预测逻辑包在滚动循环里每预测完一天就把真实的当日数据推进窗口然后重新预测下一天。这个流程模拟的是实盘中「每天收盘后更新一次预测」的状态而不是拿历史数据空想未来。def rolling_validation(model, X_full, y_full, scaler, start_idx1000): preds [] truths [] current X_full[start_idx] for i in range(start_idx, len(X_full) - 1): p model.predict(current[np.newaxis, :, :], verbose0)[0, 0] preds.append(p) truths.append(y_full[i]) # 用真实值推进窗口 —— 模拟每天拿到新数据 current np.roll(current, -1, axis0) current[-1] X_full[i 1][-1] return np.array(preds), np.array(truths)滚动验证和一次性预测的最大区别在这里current[-1]用的是真实数据而不是上一步的预测值。这样评估出来的准确率才是真实可用的因为它假设你每天都能拿到当日收盘价。用这个函数跑一遍你会立刻发现自己模型的真实水平——我实测时发现一次性预测的 RMSE 比滚动验证低 30% 左右因为一次性预测只在测试集开头输入了真实历史后面的输入全是模型自己的输出误差滚雪球。从那以后我每次拿到一个 LSTM 预测项目都会强制自己先跑滚动验证再谈准确率。不求模型真的能预测涨停但至少要知道这个模型在真实条件下值不值得信。如果滚动验证的误差在一个可接受范围这份代码就算真正被你掌握了。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询