尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

LSTM股票价格预测Python源码详解:从数据预处理到模型评估

LSTM股票价格预测Python源码详解:从数据预处理到模型评估 简介面向高校课程设计与期末大作业的长短期记忆股票价格预测Python项目提供可直接运行的完整源码与配套使用说明。项目基于长短期记忆网络实现对股票价格的建模与预测涵盖数据读取、特征处理、模型训练、结果可视化等典型环节适合需要快速搭建深度学习预测系统的学生参考。压缩包共八十九个文件大小约八点八九兆字节主要包含二十四个Python源码脚本、十九个pyc编译文件、十三个文本说明以及网页样式、表格数据、SQLite数据库等兼顾代码、文档与前端展示。已有七百三十八人学习或下载是课程设计中较受关注的选题。使用说明文档与清晰的目录结构可帮助理解整体流程下载后无需修改即可运行也可作为期末大作业的完整模板便于二次扩展与答辩演示。1. 基于LSTM的股票价格预测这个zip里到底装了什么值不值得你花时间如果你在找“基于LSTM的股票价格预测python实现源码使用说明文档.zip”大概率是已经受够了那些把股价预测写成“玄学”的文章——贴一张拟合得完美无缺的曲线然后告诉你LSTM“很厉害”却连训练集和测试集怎么切都不说。这个标题指向的东西其实是一个完整的、能跑的工程包一份Python源码外加一份使用说明文档压缩成zip分发。它解决的是“从零把LSTM时间序列预测跑起来”这件事适合三类人正在做课程设计的学生、刚接触量化交易想验证LSTM效果的散户、以及需要一份可复现基线模型的算法工程师。我见过太多人下载类似zip后卡在第一步——不是代码报错而是不知道先看哪个文件、环境怎么配、数据从哪来。这篇文章就按我实际调试这类项目的顺序把这个zip里的源码和使用说明拆开讲透怎么把股价数据变成LSTM能吃的样子的、训练时哪些参数必须调、以及那些让你怀疑人生的坑到底怎么绕过去。全文不贴完整源码因为那属于压缩包内容但给出的关键代码段足够你照着把整个流程复现出来。2. 把股价数据变成LSTM的“语言”预处理与数据集构建2.1 为什么股价序列不能直接扔给LSTMLSTM长短期记忆网络吃的是三维张量形状是(batch_size, time_steps, input_features)。但原始股价数据通常是一张二维表日期、开盘价、收盘价、最高价、最低价、成交量。如果你直接把这张表塞进model.fit()第一行就会报维度错误。更隐蔽的问题是股价序列的量纲——价格可能是几块到几千块成交量可能是几万到几亿不归一化的话LSTM的梯度更新会被大数值特征主导损失函数会像心电图一样乱跳。所以拿到压缩包里的源码第一步不是跑train.py而是看它怎么处理原始数据。常见做法是只取Close收盘价这一列做单变量预测理由是股票价格预测里“用历史收盘价预测未来收盘价”是最小可行方案如果你想用Open/High/Low/Close/Volume五维特征输入维度就变成5模型复杂度和过拟合风险都会上升。源码里的create_dataset函数一般会做这件事用一个滑窗把序列切成(样本数, time_steps, 特征数)。import numpy as np import pandas as pd from sklearn.preprocessing import MinMaxScaler def load_stock_data(csv_path): df pd.read_csv(csv_path) # 只取收盘价列并转成float32 data df[Close].values.astype(np.float32).reshape(-1, 1) return data def create_dataset(data, look_back60): 把一维序列变成监督学习样本。 look_back是时间步长即用过去多少天的数据预测下一天。 X, y [], [] for i in range(len(data) - look_back - 1): X.append(data[i:i look_back, 0]) y.append(data[i look_back, 0]) return np.array(X), np.array(y) # 归一化让数据落在[0,1]区间避免量纲影响 scaler MinMaxScaler(feature_range(0, 1)) data_scaled scaler.fit_transform(load_stock_data(stock_data.csv)) X, y create_dataset(data_scaled, look_back60) # 重塑为LSTM需要的三维格式(样本数, 时间步, 特征数) X X.reshape(X.shape[0], X.shape[1], 1) print(X shape:, X.shape, y shape:, y.shape)这段代码里有两个关键点。第一MinMaxScaler必须用fit_transform在训练集上拟合再用transform应用到测试集而不是对全量数据一次fit_transform——否则测试集的信息会被“偷看”进训练过程导致验证结果虚高。第二look_back60意味着用过去60个交易日预测下一天这个数字不是拍脑袋定的60天约等于一个季度的交易日数能覆盖中期趋势改成30会更快但对噪声更敏感改成120会引入过多历史信息导致滞后加重。2.2 训练集/测试集切分千万别随机打乱很多从分类任务转过来的人习惯用train_test_split(X, y, test_size0.2, random_state42)。这在股票预测里是致命的。时序数据的顺序蕴含了时间相关性随机打乱等于把未来数据混进训练集模型会“作弊”——它见过你要预测的那一天附近的数据测试集的预测误差会小到离谱但实盘一用就现原形。源码里的正确切分方式是按时间顺序截取前80%的数据做训练后20%做测试。这个简单规则是判断这个zip里的源码靠不靠谱的第一个试金石。# 按时间顺序切分而不是随机打乱 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:] print(f训练集样本数: {X_train.shape[0]}, 测试集样本数: {X_test.shape[0]}) # 训练集样本数: 训练序列长度 - look_back - 1 后的80%提示有些源码会在这里犯第二个错——对测试集数据也调用了scaler.fit_transform。正常的流程是训练集单独fit然后训练集和测试集共用同一个transform。切分之后还有一个容易被忽略的步骤X_train和X_test的时间步维度必须一致因为它们共用同一个look_back。如果原始数据长度不能被5整除80%切分是整数比例最后几个样本会被丢出去这不影响模型但会让你复现时发现“测试集预测结果最后少了一条”其实是边界样本被create_dataset窗口丢弃了。3. 核心源码拆解LSTM模型搭建、训练与预测流程3.1 网络结构到底要几层LSTMDropout该放哪打开压缩包里的lstm_model.py大概率会看到类似的代码结构一个Sequential先来一个LSTM层然后一个Dropout再来一个LSTM再Dropout最后Dense(1)。这是Keras里最经典的股票预测结构但层数和参数需要解释。单层LSTM对大多股票序列已经够用。两层LSTM的优点是能捕捉更高层的时间抽象但代价是参数量翻倍、训练时间变长而且在小数据集上更容易过拟合。我个人的经验是如果你手里的股票数据不到2000个交易日差不多8年用单层LSTM加Dropout足够只有数据超过5000个交易日才值得试两层。源码如果默认写了两层你可以先改成一层看效果——模型容量小了反而可能泛化更好。Dropout的位置有讲究。它应该放在两个LSTM层之间或者放在LSTM层和输出层之间而不是在LSTM内部recurrent_dropout参数。Keras的Dropout会随机丢弃输入到当前层的部分特征训练时让模型不依赖某个特定时间步recurrent_dropout丢弃的是循环连接会让训练更稳定但收敛更慢。新手源码通常只用前者。from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout def build_lstm_model(look_back60, feature_dim1): model Sequential() # 第一层LSTM返回完整序列给下一层 model.add(LSTM(units64, return_sequencesTrue, input_shape(look_back, feature_dim))) model.add(Dropout(0.2)) # 第二层LSTM只返回最后一个时间步的输出 model.add(LSTM(units64, return_sequencesFalse)) model.add(Dropout(0.2)) # 输出层单值预测 model.add(Dense(units1)) model.compile(optimizeradam, lossmean_squared_error) return model model build_lstm_model(look_back60, feature_dim1) model.summary()这段代码里return_sequences是黄金参数。第一层设成True是因为它要把每一个时间步的输出传给第二层第二层设成False是因为我们只需要最后一个时间步的输出做价格预测。如果两层都设成True输出维度会变成(batch_size, look_back, 1)和Dense(1)不匹配会报维度错误。如果两层都设成False第二层就只接收第一层最后一个时间步的输出中间序列信息全丢预测效果会明显下降。units64是常见的隐单元数它决定了LSTM记忆容量。64对小数据集足够128在数据量大时效果更好但训练明显变慢32虽然快但可能欠拟合。源码没有给你调参脚本时你可以手动改这个数字观察训练损失变化。3.2 训练参数epoch、batch_size和验证集划分模型搭好之后训练参数是第二个翻车重灾区。压缩包使用说明文档里一般会写“训练50个epochbatch_size32”但这两个值在不同长度的数据集上表现完全不同。epochs太少欠拟合太多过拟合。判断方法是看训练损失和验证损失是否能同时下降。源码如果只给一个固定的50你最好在训练时自己加一个EarlyStopping回调监控验证集损失连续10次不下降就提前停。这样既不用反复手试也能省大量时间。batch_size影响梯度更新频率和稳定性32是通用值64训练更稳但需要更大内存16会更震荡但可能跳出局部最优。还有一个关键点验证集不能从测试集里切而是从训练集尾部再切10%~20%。因为测试集是最后一段未来数据应该留到全部训练结束后才碰。这块逻辑如果源码里没有你自己加一个validation_split0.1到fit里Keras会自动取训练集最后10%做验证。from tensorflow.keras.callbacks import EarlyStopping early_stop EarlyStopping( monitorval_loss, # 监控验证集损失 patience10, # 连续10个epoch不下降就停止 restore_best_weightsTrue, # 恢复验证损失最小的权重 ) history model.fit( X_train, y_train, validation_split0.1, # 从训练集尾部切10%做验证 epochs100, # 最大epoch实际由EarlyStopping决定 batch_size32, callbacks[early_stop], verbose1 )restore_best_weightsTrue是后悔药如果不设EarlyStopping触发时模型保存的是最后一个epoch的权重而不是验证损失最低的那个权重。很多源码漏掉这个参数导致你复现时发现训练损失明明降下去了测试集预测却稀烂——就是权重被后续过拟合的epoch污染了。训练结束后预测流程有个必须处理的“逆归一化”步骤。因为模型输入输出都是缩放后的值预测出来的y_pred也在0~1之间要把它还原成真实股价必须调用scaler.inverse_transform。注意scaler是训练时拟合的那个不能重新fit否则还原出来的价格量纲全错了。# 预测测试集 y_pred model.predict(X_test) # 把预测值和真实值都还原到原始价格区间 y_pred_real scaler.inverse_transform(y_pred.reshape(-1, 1)) y_test_real scaler.inverse_transform(y_test.reshape(-1, 1)) # 看前5个预测vs真实 for i in range(5): print(f预测: {y_pred_real[i][0]:.2f}, 真实: {y_test_real[i][0]:.2f})这里有个细节scaler是用Close价格拟合的所以inverse_transform直接还原价格。如果源码用了多特征就必须分别还原对应列否则还要处理特征错位。4. 效果评估的3个指标与使用说明文档里的隐藏信息4.1 别看Loss看MAE和RMSE很多新手复现完模型盯着loss从0.01降到0.001就欢天喜地但loss是归一化空间里的均方误差数值大小和真实价格完全脱钩。给你一份使用说明文档如果它只贴loss下降曲线那这份文档大概率不专业。评估预测效果至少要三个指标。第一个是均方根误差RMSE它和股价同量纲能直观告诉你“平均预测偏差多少钱”。第二个是平均绝对误差MAE它比RMSE对异常值更稳健如果RMSE远大于MAE说明预测在某些极端日子比如暴涨暴跌上偏差极大。第三个是方向准确率股票预测里你真正关心的是“明天涨还是跌”而不是“精确到几分钱”。用y_test相邻两天的差值符号和预测差值符号对比能算出涨跌方向预测的正确率。from sklearn.metrics import mean_squared_error, mean_absolute_error import numpy as np def evaluate_model(y_true, y_pred): rmse np.sqrt(mean_squared_error(y_true, y_pred)) mae mean_absolute_error(y_true, y_pred) # 方向准确率对比相邻两天真实涨跌和预测涨跌 real_diff np.diff(y_true.flatten()) pred_diff np.diff(y_pred.flatten()) direction_acc np.mean((real_diff * pred_diff) 0) print(fRMSE: {rmse:.4f}) print(fMAE: {mae:.4f}) print(f方向准确率: {direction_acc:.2%}) return {rmse: rmse, mae: mae, direction_acc: direction_acc} evaluate_model(y_test_real, y_pred_real)注意np.diff会让序列长度减少1因为它计算的是相邻两天的差值。方向准确率能和随机猜测50%对比如果你做出一套模型长期在55%以上说明策略有统计显著性如果一直在50%附近徘徊那说明LSTM并没有捕捉到任何可交易的涨跌规律——这并不罕见很多股票序列本身接近随机游走。4.2 使用说明文档里必须有的3个内容没有就按坑处理压缩包里的使用说明文档.zip你打开后先别急着照做对照检查它有没有这三块内容。第一环境安装说明Python版本常见要求3.7~3.10、tensorflow/keras版本、pandas/numpy/sklearn版本。如果文档只说“安装requirements.txt”那这份文档及格如果连版本都没提你大概率会卡在TensorFlow 2.10以上的某个兼容性报错上。第二数据来源和格式说明它用的是什么股票、哪个时间段、CSV里有哪些列、日期格式是YYYY-MM-DD还是时间戳。很多源码自带的stock_data.csv只有收盘价但你的真实股票数据是从tushare、akshare或者Yahoo Finance下载的列名可能是close而不是Close这时你要自己改源码里的列名映射。第三使用步骤是不是明确写了“先运行preprocess.py再运行train.py最后运行predict.py”。如果文档把三个步骤混在一段文字里你复现时会来回试错。遇到这种文档我一般会先看源码里的if __name__ __main__部分执行顺序在那里最清楚。5. 从下载到跑通的完整实操环境配置、文件解压和踩坑记录5.1 环境配置Python版本和TensorFlow的恩怨先说一个最常见的致命伤直接双击train.py报ModuleNotFoundError: No module named tensorflow。这不是源码问题而是环境里没装库。这里的标准做法是新建虚拟环境把依赖锁在项目内部不要污染系统Python。# 创建虚拟环境python版本建议3.8或3.9 python3.9 -m venv lstm_env # 激活环境 source lstm_env/bin/activate # Windows下用 lstm_env\Scripts\activate # 安装核心依赖版本号按压缩包内文档调整 pip install tensorflow2.10.0 pip install pandas numpy scikit-learn matplotlibTensorFlow版本是最大的坑。2.10是最后一个原生支持Windows GPU的版本2.11以后在Windows上只能用CPU版如果你装了2.15在Windows上调用GPU会直接忽略甚至报错。而CPU训练LSTM一个2000样本的数据跑50个epoch可能要10分钟GPU只需要1分钟。所以你先确认文档写的版本如果没写请装2.10。另外Python 3.11以上不能直接pip install tensorflow2.10因为官方包不提供3.11的轮子——这也是为什么我建议Python 3.8/3.9。装完库之后可以先跑一个极小火烧测试把look_back改成10epochs改成2看能不能走通训练和预测流程。这个测试的意义是区分“代码逻辑问题”和“训练时间问题”而不是一上来就全量跑然后干等。5.2 zip解压与文件完整性伪加密和路径过长压缩包如果是从网盘下载的解压时可能遇到两个级别的问题。级别一zip文件声称有密码但你明明没有设置过密码。这种叫“伪加密”常见于某些分享者为了防在线预览而抹了个标志位实际密码为空。用7-Zip打开如果能看到文件名列表但提示密码试试直接回车确认空密码如果不行用系统自带tar命令在Linux下解压可能会绕过伪加密标志。级别二Windows解压时提示文件名太长或路径无效。罪魁祸首是压缩包内部嵌套了多层目录比如stock-prediction-lstm-master/stock-prediction-lstm-master/..../data/stock_data.csv解压后全路径超过260字符。解决办法是解压到短路径比如C:\lstm\而不是C:\Users\你的用户名\Downloads\股票预测项目\v1.0\...。这个坑在zip类项目包里极其常见。# Linux/macOS下解压并重命名顶层目录 unzip 基于LSTM的股票价格预测python实现源码使用说明文档.zip -d /tmp/stock_lstm cd /tmp/stock_lstm # 看看有没有冗余的嵌套目录 find . -maxdepth 3 -type d | head -205.3 踩坑记录3条高频翻车现象与解决第一个高频坑ValueError: operands could not be broadcast together with shapes (x,x) (y,y)。现象是预测完做inverse_transform时维度对不上。原因多半是y_pred的形状是(样本数, 1)而y_test在某个处理环节变成了(样本数,)。解决方法是预测后统一y_pred.reshape(-1, 1)真实值同样y_test.reshape(-1, 1)再去做逆变换。第二个高频坑NaN loss。现象是训练过程中损失变成nan然后模型输出全是nan或垃圾值。原因通常是数据里有NaN或无穷值没有清洗或者归一化时除数为零某列全相同。解决方法是读入数据后立即df.isnull().sum()检查并填充或删除异常值。另外如果learning_rate设得太大比如默认adam的0.001在某些数据上也可能偏大试着调低到0.0001。第三个高频坑预测曲线比真实曲线滞后一天。现象是画图时预测线整体右移看起来像真实线的“延迟复制”。原因是LSTM的损失函数是最小化均方误差它学到的最优策略是“重复昨天的价格”因为股价序列自相关性高用昨天的值预测今天误差往往最小。这个不是代码bug而是任务本身的陷阱。缓解方法是不要只做单步预测改成多步预测预测未来5天或10天或者把损失函数改成方向损失——直接惩罚“预测涨却跌了”的情况。但这个在源码里基本不会实现你需要自己改。6. 把这个zip用出价值多步预测与模型结果的可视化验证6.1 从单步预测到序列预测滑窗滚动测试集评估阶段源码里通常是拿X_test直接一次性预测出所有样本输出(样本数, 1)。这只验证了“已知过去60天、预测下一天”的准确率。但实盘你不可能每天都等到真实数据更新后再预测一次你得做“滚动预测”用前60天预测出第61天然后把第61天的预测值拼进输入序列再预测第62天以此类推。这样做5天、10天的预测才能真实反映模型在长时间范围内的表现。def rolling_predict(model, last_sequence, scaler, steps5): last_sequence: 最近look_back天的归一化序列 steps: 要预测未来几天 predictions [] current_seq last_sequence.copy() for _ in range(steps): # 输入模型预测下一天 pred model.predict(current_seq.reshape(1, current_seq.shape[0], 1)) predictions.append(pred[0, 0]) # 把预测值追加到序列末尾移除最前面的旧值 current_seq np.append(current_seq[1:], pred[0, 0]) # 还原成真实价格 return scaler.inverse_transform(np.array(predictions).reshape(-1, 1))这里有个关键点滚动预测时每一步的输入都包含上一步的预测值所以误差会逐步累积。预测第一步可能误差只有0.5%到第5步可能变成3%。这是正常的滚动步数越长不确定性越大。如果你画出来的5步预测曲线依然和真实曲线贴得很近那大概率是单步预测的“延迟复制”现象造成的假象——真实线滞后一天多步滚动后反而对上了这并不能证明模型有预测能力。6.2 把预测结果画出来的三个细节使用说明文档里一般会附带plot_predictions.py用来画训练集和测试集的拟合曲线。画图本身简单但有三点要注意。第一训练曲线只画训练集范围内的拟合别把训练集的预测和测试集的预测混在一张图里不区分颜色——否则你会误以为模型预测得很完整其实训练集部分是“背书”测试集部分才是真考验。第二纵轴是价格横轴是样本序号而不是日期如果你想让别人看懂要把日期索引映射回去。第三预测线用虚线真实线用实线颜色要有明显区分否则灰度打印后根本分不清。import matplotlib.pyplot as plt # 假设已有 y_test_real 和 y_pred_real plt.figure(figsize(12, 5)) plt.plot(y_test_real, colorblue, labelReal Price) plt.plot(y_pred_real, colorred, linestyle--, labelPredicted Price) plt.title(LSTM Stock Price Prediction on Test Set) plt.xlabel(Sample Index (Test Period)) plt.ylabel(Price) plt.legend() plt.grid(True) plt.savefig(prediction_result.png, dpi150) plt.show()画完图之后别只靠眼睛判断“看起来挺贴的”。我习惯把预测误差按日期的绝对值画出来如果误差集中在某一时段比如财报发布日附近说明模型对突发事件没有感知LSTM只适合捕捉趋势不适合预测跳空。6.3 最后说一个必须养成的习惯下载这个zip、跑通源码、得到一张好看的预测图其实只完成了30%的工作。剩下70%是你要拿着这套代码去换数据、换股票、调参数直到你弄清楚它的边界。所谓“边界”就是在哪类股票上有效趋势型白马股往往比题材股效果好在哪类行情下失效长期横盘时模型会退化到“预测昨天”以及训练时长和数据量的关系。我会在每跑完一组实验后把look_back、units、epochs、RMSE、方向准确率记在备注里一个月后回看就能慢慢摸到规律。如果你是从零开始第一次跑LSTM股票预测希望你跑通这个zip之后不要急着拿它去做实盘决策——先用模拟数据验证你有能力判断“这个模型什么时候会失效”。希望这篇笔记能帮你把这个压缩包真正变成自己的工具箱而不仅仅是解压过一次的文件夹。本文还有配套的精品资源点击获取
返回列表