多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

LSTM股票预测课程设计实战:从数据预处理到模型评估

LSTM股票预测课程设计实战:从数据预处理到模型评估 简介时间序列预测是机器学习的重要分支股票价格作为典型非线性、非平稳序列其预测任务极具挑战性。传统方法如ARIMA对数据平稳性要求苛刻而LSTM凭借其独特的门控机制与记忆单元能够有效捕捉长短期依赖关系成为金融时序预测的主流模型。在实际工程中特征工程的质量往往决定模型上限从OHLCV到技术指标MA、RSI再到归一化与滑窗切分每一步都直接影响预测精度。此外正确处理训练集与测试集的归一化、防止数据泄漏以及合理评估MAE、RMSE、方向准确率等指标是构建可靠模型的关键。本文以LSTM为核心系统梳理了股票预测课程设计的完整流程从数据获取到模型评估为深度学习实践提供了一份可复用的技术路线。1. 为什么是LSTM先把模型的选型逻辑讲清楚做股票预测这个题目最怕的不是写不出代码而是交上去的作业一眼看上去就是“拼凑的demo”。老师翻代码的时候重点看的不是你调了多少个包而是你能不能讲清楚每个环节的选择理由。LSTM之所以成为这类课程设计的主流选择核心原因就一句话股票数据是典型的时间序列而LSTM天生就是处理时间序列的结构。很多人一开始想的是用普通全连接网络去预测或者用ARIMA这种传统统计模型。全连接网络的问题在于它把每个时刻的数据当成独立的样本完全丢掉了时间上的先后依赖关系。今天的收盘价对明天的收盘价有影响这周的走势对下周的趋势有牵引这种“记忆”能力是普通网络不具备的。ARIMA虽然是时间序列的经典方案但它对数据的平稳性要求很苛刻股票价格这种非平稳、带噪声、有波动聚集效应的序列ARIMA做起来非常吃力差分阶数、滞后阶数都要反复调而且预测长序列的能力有限。LSTM走的是另一条路。它内部有输入门、遗忘门、输出门三个门控结构配合一个贯穿时间步的记忆单元让网络能够在长序列中保留需要的信息、丢弃无关的信息。对股票这种“短期波动大、长期有趋势”的数据LSTM能在一定程度上捕捉到均值回归效应和趋势延续效应。用大白话讲它学会了“该记的记该忘的忘”。我见过不少同学在答辩的时候被问“你为什么不用GRU”“LSTM和RNN什么区别”如果只是照本宣科背定义很容易被追问到卡壳。我的建议是这个项目里你用LSTM做主力模型报告里再补一组对比实验——拿简单的线性回归或者单层LSTM做对照——不需要做得太复杂但“对比”这两个字在评分标准里往往直接对应“工作量充足”和“有独立思考”两个加分项。后面我会详细讲怎么设计对比实验。2. 从数据到特征90%的分数藏在数据准备里2.1 数据源怎么选免费稳定好解释是第一原则数据是整份作业的地基。我见过太多人卡在数据获取这一步原因无外乎三种接口没权限、字段看不懂、数据格式不统一。以我实测过的体验来说推荐优先用Tushare Pro或者AkShare。Tushare Pro需要注册账号拿一个token部分接口有积分要求但基础日线数据注册后就能用AkShare完全免费不需要token直接pip安装就能拉数据。如果你只是做课程设计不需要上亿条数据这两个都够用。选数据源的时候有一个重要的考量维度可复现性。你的老师打开你的代码重新跑一遍能不能顺利拿到同样的数据如果用的是某个需要付费权限的接口老师没有token代码直接报错印象分会掉很多。所以我的建议是把拉取到的数据本地存一份CSV代码里写清楚“优先读本地缺失时再从接口拉”把数据快照放在项目目录里一起提交。这样既保证了复现又展示了工程意识。单只股票还是多只股票课程设计一般不需要做全市场预测选一只流动性好的股票即可比如贵州茅台、招商银行、平安银行之类的。有波动才有预测空间天天横盘的股票预测了也没意义。时间范围建议取最近三到五年覆盖至少一段完整的上涨和下跌周期这样模型能学到不同市场环境下的特征。2.2 特征工程价格之外还能加什么原始数据拉下来一般有这几列日期、开盘价、最高价、最低价、收盘价、成交量、成交额。初学者最容易犯的错误就是只用收盘价一个字段去预测收盘价信息量太少模型很难学到东西。常用特征至少包括以下几类OHLCV原始序列开盘、最高、最低、收盘、成交量衍生特征涨跌幅、振幅、换手率、量比技术指标MA5、MA10、MA20、MACD、RSI、布林带位置时间特征星期几、月份用来捕捉周内效应和月度效应技术指标不建议堆太多选五六个有代表性的就够了。特征太多会引入噪声训练速度变慢还容易过拟合。以我个人的经验MA5、MA20、RSI、MACD这四个技术指标配合原始OHLCV已经能拿到不错的效果。有一个细节很多人不知道特征选择的时候一定要想清楚“这个特征在预测时能不能拿到”。比如你用“当日成交量”去预测“次日收盘价”这是合理的因为当日数据是已知的但如果你不小心把“次日开盘价”也放进特征里那就发生了数据泄漏data leakage训练时指标很好实际预测时发现根本拿不到这个特征。老师最喜欢问的就是“你的特征里有没有未来数据”这个问题答不好分数档次直接掉一级。2.3 归一化必须只对训练集拟合这是最容易扣分的点LSTM用的是激活函数对输入数据的尺度非常敏感。股票价格是几千甚至几万的数量级如果直接塞进网络梯度计算很容易出问题训练不稳定。所以归一化是必需的通常用MinMaxScaler把所有特征缩放到0到1之间。但这里有一个极其关键、期末作业里最常见的扣分点MinMaxScaler必须只在训练集上fit然后再用同一套参数去transform验证集和测试集。很多人的代码写成先对整个数据集做归一化再划分训练测试集这属于典型的“信息泄漏”——测试集的信息在训练阶段就已经被模型看到了评估结果会虚高。真实场景中你没有未来数据不可能拿未来的最大值最小值来归一化过去的数据。正确做法是先按时间顺序划分训练集和测试集再在训练集上fit scaler然后transform所有集合。我建议把这段逻辑写在代码注释里答辩的时候主动提一句“我特意避免了归一化泄漏”这个细节能让你从八十分档跳到九十分档。2.4 滑窗切分如何把时间序列变成模型能吃的样本LSTM的输入是三维的形状是[样本数, 时间步长, 特征数]。时间步长就是“用过去多少天的数据去预测未来”比如用过去20天的数据预测明天的收盘价那时间步长就是20。滑窗的原理很好理解假设有1000天的数据窗口长度20那么第1到20天生成第一个样本第2到21天生成第二个样本依此类推总共生成约980个样本。这个滑动的过程需要自己写或者用keras.preprocessing.timeseries_dataset_from_array来生成。窗口长度怎么选太短模型看不到趋势太长样本数量变少训练效率低而且股票市场的“记忆”本身也有限十年前的价格对明天的影响微乎其微。我的经验是5到60天之间具体取值可以做一个小实验分别比较窗口为5、10、20、30天时的验证集误差把对比结果写进报告里又是一个加分项。预测目标怎么定最常规的设定是“预测明天的收盘价”这是回归任务。除此之外还可以做二分类——预测明天涨还是跌甚至多分类——预测涨幅区间。课程设计首选回归因为回归的误差指标更直观画图也更漂亮分类可以作为扩展实验写进第四章。3. LSTM模型搭建从架构设计到训练细节3.1 网络结构几层LSTM、多少个神经元才算合理网络结构没有标准答案但有一个合理的起点。以我的经验和多轮实测来看单层LSTM加一个Dense输出层在大部分股票数据上已经能取得不错的效果。堆两层LSTM往往能提升一点点精度但训练时间翻倍而且更容易过拟合。课程设计建议先从单层开始如果效果不理想再加深。具体参数我推荐这样起步第一层LSTM50个神经元return_sequencesTrue第二层LSTM50个神经元可选加了就return_sequencesFalseDropout层0.2防止过拟合Dense输出层1个神经元线性激活输入形状不用在LSTM层里显式指定Keras会根据输入数据自动推断。但如果你写了Input层记得把形状写成(time_step, feature_dim)。神经元数量怎么调一个简单原则先定一个小值比如32看训练集loss能不能降下去能降说明模型容量够用如果验证集loss高而训练集loss很低那是过拟合需要加Dropout或减小模型如果训练集loss也降不下去说明模型容量不够需要加大。3.2 损失函数和优化器这些参数为什么这么选股票预测是回归任务最常用的损失函数是均方误差MSE。为什么不用MAE因为MSE对大误差的惩罚更大梯度更平滑训练更稳定。但MSE对异常值敏感股票数据里偶尔会有极端行情如果你发现模型被个别极端值带偏了可以换成Huber Loss它是MSE和MAE的折中。答辩的时候能说清楚MSE和Huber的区别非常加分。优化器直接用Adam学习率默认0.001即可。注意不要自己瞎改学习率策略除非你明确知道为什么要改。Adam自带自适应学习率对新手非常友好。编译代码我习惯这样写from keras.losses import MeanSquaredError from keras.optimizers import Adam model.compile( optimizerAdam(learning_rate0.001), lossMeanSquaredError(), metrics[mae] )除了loss一定要加mae这个指标。理由是MSE是平方量纲直观上不好理解而MAE直接从预测值和真实值的平均绝对误差出发人话就是“平均每天预测错了多少钱”老师和同学都能一眼看懂。3.3 训练细节EarlyStopping和模型保存不能少训练轮数epochs不是越大越好。我见过有人直接训500轮训到后面验证集loss不降反升典型的过拟合。正确做法是配合EarlyStopping使用监控验证集loss如果连续多轮没有改善就停止训练同时恢复到最佳权重。代码示例from keras.callbacks import EarlyStopping, ModelCheckpoint early_stop EarlyStopping( monitorval_loss, patience20, restore_best_weightsTrue ) checkpoint ModelCheckpoint( best_model.h5, monitorval_loss, save_best_onlyTrue ) history model.fit( X_train, y_train, validation_data(X_val, y_val), epochs150, batch_size64, callbacks[early_stop, checkpoint], verbose1 )batch_size的选择也有讲究。股票数据样本量一般几千到几万batch_size设64或128比较合适。太小训练不稳定太大训练太慢而且容易陷入局部最优。训练完之后画loss曲线是必须的——训练loss和验证loss两条曲线画在同一张图上。如果训练loss下降而验证loss先降后升就是过拟合如果两条线都降不下去就是模型容量不够或学习率不合适。这张图是报告里的标配也是老师判断“你确实动手训练过”的重要依据。3.4 反归一化预测值必须还原成真实价格再评估模型输出的预测值是0到1之间的归一化数值必须用之前那个scaler做inverse_transform才能回到真实价格量纲。这里要注意一个坑如果训练时随机选了多个特征一起归一化inverse_transform需要传入和之前相同维度的输入。所以实践中常见做法是预测目标收盘价单独用一个scaler其余特征用另一个scaler这样反归一化时不容易出错。代码逻辑大致是这样pred_scaled model.predict(X_test) pred_price target_scaler.inverse_transform(pred_scaled.reshape(-1, 1)) real_price target_scaler.inverse_transform(y_test.reshape(-1, 1))反归一化之后再算误差指标、画预测对比图结果才是真实可读的价格数字。4. 评估与可视化用跌宕起伏的曲线让老师眼前一亮4.1 误差指标MAE、RMSE、MAPE都要会解释评估指标是报告里必备的内容但很多人的通病是光贴数值不解释含义。每个指标都要一句话说清楚“它到底在衡量什么”。MAE是平均绝对误差单位是元意思是预测值和真实值平均差多少钱。RMSE是均方根误差它比MAE对大误差更敏感如果RMSE明显大于MAE说明预测里存在一些特别离谱的样本。MAPE是平均绝对百分比误差它消除了价格量纲的影响方便和其他股票对比比如MAPE2%意味着平均每天预测偏了2%。R²决定系数用来衡量模型对数据的解释程度越接近1越好。对于课程设计我建议报告里用表格列出这几个指标同时加一句“从数据可以看出模型在测试集上MAPE为X%说明预测误差在可接受范围内”。注意不建议说“预测很准”这种绝对化的话股市本身带有随机性老师也清楚这一点。你的目标是展示“我能科学评估一个模型的效果”而不是宣称“我找到了股市提款机”。代码示例from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score import numpy as np mae mean_absolute_error(real_price, pred_price) rmse np.sqrt(mean_squared_error(real_price, pred_price)) mape np.mean(np.abs((real_price - pred_price) / real_price)) * 100 r2 r2_score(real_price, pred_price)4.2 预测曲线图这张图画好了答辩就成功了一半可视化是课程设计里最直观的评分依据。我见过很多代码写得一般、但图特别漂亮的作业拿到高分也有代码很完整但图一塌糊涂的作业被压分。图是你的脸面值得花时间打磨。核心图至少要有四张第一张是原始价格走势图让读者对数据总体情况有认识。第二张是训练集真实价与预测价的对比图主要证明模型学习了训练数据。第三张是测试集真实价与预测价的对比图这是最有说服力的一张图用来证明模型的泛化能力。第四张是误差分布图可以画预测残差的直方图直观呈现误差是否符合正态分布。测试集对比图我建议只画最后200到300个交易日否则整条曲线挤在一起看不出细节。画法示例import matplotlib.pyplot as plt plt.figure(figsize(12, 6)) plt.plot(real_price, labelTrue Price, colorblack, linewidth2) plt.plot(pred_price, labelPredicted Price, colorred, linestyle--) plt.title(LSTM Stock Price Prediction on Test Set) plt.xlabel(Time Step) plt.ylabel(Price (CNY)) plt.legend() plt.grid(alpha0.3) plt.tight_layout() plt.savefig(prediction_result.png, dpi200)注意图片要设置dpi200以上清晰度直接影响印象分。坐标轴要有明确标签图例一定要加这些都是基本的学术作图素养。4.3 方向准确率股票预测里更贴近实际场景的指标价格预测的误差再小如果预测涨跌的方向经常反了实际参考价值就不大。所以在评估环节我强烈建议加一个“方向准确率Directional Accuracy”指标计算方式很简单判断模型预测的明日价格相对于今日是涨还是跌跟真实方向是否一致统计一致的比例。这个指标不需要额外写复杂代码几行就能算出来true_direction np.sign(np.diff(real_price.flatten())) pred_direction np.sign(np.diff(pred_price.flatten())) accuracy np.mean(true_direction pred_direction) * 100为什么这个指标重要因为股票预测的终极目标不是预测精确价格——那几乎不可能——而是预测趋势。方向准确率超过55%就已经有实际参考价值了这个数字在答辩时非常能说明问题。4.4 策略回测把预测结果转化为模拟收益如果想让作业再往上一个档次加一个策略回测模块。思路很简单如果模型预测明天上涨就模拟持有如果预测下跌就模拟空仓或卖出。对比“模型策略”和“一直持有不动”的累计收益画两条净值曲线。这是很多课程设计里没有的内容一旦出现就属于“加分项中的加分项”。代码也不复杂核心逻辑是根据预测方向生成每日持仓状态然后乘以当日的实际收益率。注意这里是为了展示模型的实用价值不是让你真金白银去炒股报告中要加一句“策略模拟仅用于学术研究不构成投资建议”。5. 课程设计拿高分的四个隐藏技巧5.1 报告结构要让老师五分钟内看懂所有亮点95分以上的期末作业报告结构通常遵循一个黄金公式先交代问题和意义再介绍数据来源和预处理方法然后用图表呈现模型结构接着展示实验结果和对比分析最后写不足与展望。报告里要有至少三张图、两张表。图分别是数据走势图、预测对比图、loss曲线图表分别是模型参数表和指标对比表。这三图两表就是报告的主干其他文字都是围绕他们展开。有一个常见错误一上来就贴大段代码。老师要看的不是代码是思路和结果。代码放附录正文只放核心代码片段。5.2 对比实验同一模型少参数就不如多参数这是最有效的论证“没有对比就没有伤害”这句话在学术场景里完全成立。一份只说“我做了LSTM预测模型”的作业和一份说“我对比了单层LSTM、双层LSTM、不同时间步长、是否加技术指标的效果”的作业评分差距往往是两个档次。我在前面提过对比实验不需要多复杂三条线就够基准线单层LSTM 只用收盘价相当于最简方案主力方案单层LSTM 完整特征集OHLCV 技术指标扩展方案双层LSTM 完整特征集把三个方案在测试集上的MAE、RMSE、MAPE放进同一个表格配合一段分析文字说明“增加特征能够有效降低预测误差但增加LSTM层数对效果的提升有限说明当前瓶颈在特征而非模型复杂度”。这段话展示了你对模型的深度理解比任何代码都能打动老师。5.3 答辩预演把最可能被问到的6个问题准备成问答稿答辩环节决定最终印象分。我按多年经验整理出最常被问的问题提前准备就不会慌。第一个问题是“为什么选LSTM而不选RNN或GRU”。回答要点是LSTM的门控机制能缓解梯度消失GRU虽然结构更简单速度更快但在长序列上LSTM的经验表现更稳定。第二个问题是“你的模型有哪些局限性”。诚恳认错反而加分可以说模型没有考虑市场消息面因素、宏观经济指标无法应对极端行情。第三个问题是“滑动窗口长度怎么定的”。你要能说出是做了实验对比不是随便拍的。第四个问题是“怎么防止过拟合”。答Dropout、EarlyStopping、数据量控制。第五个问题是“如果预测不准怎么办”。答这个预测只作为参考方向准确率比精确价格更有意义。第六个问题是“这套方法能直接用来炒股吗”。答案是明确的“不能”股市受太多未知因素影响做作业是证明建模能力不是创造永动机。5.4 代码规范命名清晰、注释到位、结构分层对于一个直接读你代码的老师来说代码结构比代码本身更值钱。我建议把所有代码分成四个文件data_fetcher.py管数据获取data_preprocess.py管清洗和滑窗生成model.py管模型搭建和训练evaluate.py管评估和画图。再加一个main.py串联整个流程一个README.md说明运行环境和步骤。注释要写中文关键步骤写清楚“为什么”而不是“做了什么”。比如归一化那行注释写“只在训练集上拟合防止测试集信息泄漏”这句话的价值远超代码本身。变量命名用英文不要用拼音缩写。这些工程上的细节虽然不影响预测结果但直接影响老师对你专业素养的判断。6. 常见问题与调试技巧实录6.1 维度报错LSTM输入必须是三维的这是新手第一大坑报错信息里最容易遇到的是Input 0 of layer lstm is incompatible with the layer: expected ndim3, found ndim2。这个错误就是在告诉你LSTM需要三维输入(batch_size, time_step, n_features)而你给的是二维数据。解决办法很简单在特征矩阵准备好之后用reshape把数据变成三维。比如你有1000个样本窗口长度20特征数10那形状应该是(981, 20, 10)因为最后一个样本的起点是第981个样本。如果你发现数据的形状对不上优先回看滑窗切分的实现。6.2 过拟合训练集loss一直降验证集loss在后半段不降反升这是LSTM做股票预测时最典型的问题。股票数据本身就带噪声模型容易把噪声中的偶然规律也学进去。解决手段按优先级排列加Dropout0.2起步可以试0.3、调低LSTM神经元数量、EarlyStopping的patience调小一些、增加训练数据量。还有一个被忽视的手段是降低batch_size小batch引入的随机性有时反而能帮助模型跳出局部最优。如果试遍以上手段还是过拟合检查一下是否用了过多的技术指标特征。特征越多模型可拟合的维度越高但股票数据没有那么多稳定的规律可学特征多到一定程度就是在帮噪声建模。6.3 loss不降检查两点学习率和数据归一化状态loss一直不降或者剧烈震荡第一反应不是调模型结构而是检查两件事。第一数据是否归一化。我见过一次真实案例同学忘了对数据做归一化直接训练loss在几十万上下震荡了100轮毫无改善。第二学习率是否过大或过小。默认的0.001一般没问题但你如果改到0.1可能梯度爆炸改到0.00001可能训练速度慢到你怀疑人生。还有一个容易忽略的点检查标签列是否也做了归一化。有时候特征归一化了但y忘了归一化模型输出范围是0到1而真实价格是几十块钱损失函数爆炸。这个细节非常常见。6.4 预测结果是一条水平线模型输出几乎不变重点检查这三点这种情况我也踩过坑。如果预测曲线几乎是一条平线说明模型学到了“输出均值最优”也就是预测结果基本贴近历史均值的简单策略。原因往往有三个特征完全没有预测力、模型容量太小或者特征归一化包含未来信息然后又反归一化出错。还有一个低级的坑用MinMaxScaler归一化后预测值反归一化时传入了错误的特征维度导致输出全部被拉伸到同一个值。检验方法很简单把预测值在归一化之前打印出来看看是否在0到1之间变化。如果归一化之前的预测值有波动那问题出在反归一化如果归一化之前就是平的那问题出在模型或特征。7. 代码压缩包交付的注意事项题目里带了.zip后缀说明这份作业最终是以压缩包形式提交的。我拿到过很多份课程设计发现压缩包内的组织方式本身就是隐形评分项。包里建议至少包含这些内容完整的源代码目录、一份requirements.txt环境依赖文件、一份README.md运行说明、一份项目报告PDF和Word双版本、核心结果图预测曲线、loss曲线、如果数据集不大的话把本地数据CSV也放进去。requirements.txt这个文件特别提一下很多同学会忽略。老师在一台新电脑上跑你的代码如果少了环境依赖说明光是装tensorflow、pandas就能折腾半小时如果恰好版本不对还报一堆错体验分直接崩。写清依赖文件至少保证老师能在二十分钟内跑通全流程。numpy1.24.3 pandas2.0.3 scikit-learn1.3.0 matplotlib3.7.2 tensorflow2.13.0压缩包命名也要注意如果学校支持文件名尽量包含学号姓名和项目名方便老师归档。在实际操作中我还发现一个非常实用的小技巧在README.md里写清楚“先运行main.py一键训练再运行evaluate.py查看结果”并附上实测运行环境的说明比如Python版本3.10、操作系统Windows 11。这种细节看起来不起眼但老师打开压缩包那一刻的体验会直接影响他对整个项目的心理预判。本文还有配套的精品资源点击获取
返回列表