ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LSTM股票预测期末大作业高分指南:数据预处理到模型调优全流程复盘

2026/8/30 6:15:15 拓冰建站 浏览量
LSTM股票预测期末大作业高分指南:数据预处理到模型调优全流程复盘 简介本资源是一份基于LSTM神经网络的股票价格预测模型Python实现专为高校计算机、金融工程或人工智能方向学生设计适用于期末大作业、课程设计及毕业设计参考。项目已获97分高分评价完整复现了数据预处理、序列建模、训练调优与可视化预测全流程具备较强工程落地性与教学示范性。压缩包共12个文件含3个核心Python源码含主训练脚本与预测模块、2个CSV历史行情数据上证指数与单支股票、1个Word版详细说明文档、1个模型检查点及配套meta/index文件整体仅961KB轻量易部署。已有1082人学习下载内容结构清晰从原始数据加载、滑动窗口构造、LSTM模型定义到结果绘图与误差评估一应俱全附带可直接运行的demo脚本与编译缓存文件显著降低复现门槛是理解时序预测实战的优质入门范例。 先把这个期末大作业当项目做别当“交差”的作业做。同样是LSTM股票预测有人拿95分有人拿85分差距不在模型本身而在于你有没有把“预测”这件事讲透。这篇内容我按完整的项目复盘来写包含了我自己当时踩过的坑、查过的资料、最后总结出的高分套路你可以直接照着复现也可以在此基础上加自己的东西冲更高分。1. 项目整体设计与评分点拆解1.1 拿到题目后首先想清楚的事LSTM股票预测这个题目每年都有人做但大多数人只是跑通了一个模型就交上去了。要想拿95分以上你需要理解评分老师在看什么。期末大作业的评分维度通常分为以下几块选题意义与问题定义约15分、数据获取与预处理规范性约20分、模型设计与参数解释约25分、实验对比与结果分析约25分、代码规范与报告撰写约15分。很多人在第一块就吃了亏开篇就写“股市风险大预测很重要”这话没错但太空了。你要做的是把问题定义清楚是预测收盘价还是预测涨跌方向是用前N天数据预测后一天还是预测未来一周趋势问题定义不同模型设计完全不同评分老师一眼就能看出你有没有想清楚。1.2 技术选型为什么选LSTM时间序列预测的模型有不少选择ARIMA、Prophet、XGBoost都能做但LSTM在这个题目里有天然优势股票数据是典型的时间序列存在长期依赖关系LSTM的门控机制天然适合捕获这种依赖LSTM能处理变长序列不像ARIMA有严格的平稳性要求相比普通RNNLSTM解决了梯度消失问题训练更稳定深度学习模型的“黑盒”特性反而给了你更多分析空间可视化、注意力等但要注意用LSTM不意味着可以忽略传统方法。一个能拿高分的大作业通常还包含一个对比实验LSTM vs ARIMA vs 线性回归。哪怕ARIMA效果更好你也需要通过分析来解释“为什么在这个数据集上LSTM没打赢传统模型”这本身就是深度学习的价值体现。1.3 项目目录与交付物的规划先把目录结构规划好避免中途写乱了stock_prediction_project/ ├── data/ # 原始数据与处理后的数据 │ ├── raw/ # 从tushare或yfinance下载的原始数据 │ └── processed/ # 归一化、滑窗后的数据 ├── src/ # 源代码 │ ├── data_fetcher.py # 数据下载模块 │ ├── preprocess.py # 数据预处理模块 │ ├── model.py # LSTM模型定义 │ ├── train.py # 训练脚本 │ ├── evaluate.py # 评估与可视化 │ └── utils.py # 工具函数 ├── checkpoints/ # 模型权重保存 ├── figures/ # 生成的图表论文/报告用 ├── requirements.txt # 依赖清单 └── README.md # 项目说明这个结构向老师传递了一个信息你是按工程化标准做的不是把代码堆在一个.ipynb里。这也是加分项。2. 环境配置与数据获取把这些基础做到滴水不漏2.1 Python环境配置的坑环境配置是最容易翻车的地方也是很多同学一开始就卡住的地方。建议直接用Anaconda创建独立环境不要用系统全局的Python因为后面装TensorFlow/PyTorch时会因为依赖冲突整得焦头烂额。conda create -n stock_lstm python3.9 conda activate stock_lstm pip install tensorflow pandas numpy matplotlib scikit-learn tushare这里说一下版本选择的问题TensorFlow的版本不要太新很多老教程用的还是2.4/2.5如果你装了2.10以上版本有些API接口会不一样比如tf.keras的使用方式但from tensorflow.keras这种写法在2.x都兼容。如果你用PyTorch也可以但LSTM的搭建代码要相应调整。提示如果你的网络环境访问外网有问题下载TensorFlow可能很慢镜像源是最快的解决方案。用清华或阿里云的镜像源pip install -i https://pypi.tuna.tsinghua.edu.cn/simple tensorflow2.2 数据源选择免费且合规的获取方式股票数据获取必须注意合规性问题。几个常见的数据源Tushare国内最常用的免费数据源注册即用积分够的话可以获取很细粒度的数据AKShare完全免费无需注册但接口变动比较频繁yfinanceYahoo Finance需要能访问外网不推荐baostock国内免费数据源接口稳定适合做期末作业我的建议是用Tushare或者AKShare因为数据是A股的真实行情报告里可以写清楚“数据来源Tushare Pro API”导师看了觉得规范。Tushare的代码示例import tushare as ts import pandas as pd # 需要先在tushare.pro注册获取token ts.set_token(你的token) pro ts.pro_api() # 获取平安银行2020-2023年的日线数据 df pro.daily(ts_code000001.SZ, start_date20200101, end_date20231231) df df.sort_values(trade_date).reset_index(dropTrue) print(df.head())如果你不想注册也可以用AKShareimport akshare as ak # 获取贵州茅台历史数据 df ak.stock_zh_a_hist(symbol600519, perioddaily, start_date20200101, end_date20231231, adjustqfq) df df.rename(columns{日期: date, 收盘: close}) print(df.head())2.3 股票代码选择的思路选择哪只股票也是有讲究的。建议选流动性好、数据量大、趋势相对明显的股票比如贵州茅台600519、平安银行000001、招商银行600036。不要选ST股或次新股因为数据可能有异常。我当时选的是平安银行原因很简单数据平稳、受大盘影响明显LSTM能学到一些规律。更重要的是平安银行的历史数据里包含了几次明显的涨跌周期这让预测结果可视化时看起来“有故事可讲”。3. 数据预处理这步决定了你模型的上限3.1 缺失值与异常值处理获取到的原始数据通常不会直接可用。我拿到数据后第一件事是做数据检查# 检查缺失值 print(df.isnull().sum()) # 检查数据量 print(f数据量: {len(df)}) print(f时间范围: {df[trade_date].min()} ~ {df[trade_date].max()})缺失值的处理方式如果缺失的是非交易日周末、节假日不需要填充因为股票数据本身就是按交易日排列的如果是交易日缺失用前向填充ffill或插值。3.2 为什么一定要做归一化这是很多初学者的知识盲区但在报告里写清楚了是加分项。LSTM使用tanh和sigmoid作为激活函数它们的输出范围是[-1, 1]或[0, 1]。如果输入数据不归一化股价动辄几十、几百梯度会非常大训练过程很容易震荡甚至发散。归一化让所有特征处在同一量纲下模型收敛更快训练更稳定。常用的归一化方法有两种from sklearn.preprocessing import MinMaxScaler, StandardScaler # 方法1MinMaxScaler将数据缩放到[0,1] scaler MinMaxScaler(feature_range(0, 1)) scaled_data scaler.fit_transform(df[[close]].values) # 方法2StandardScaler标准化为均值为0方差为1 # scaler StandardScaler() # scaled_data scaler.fit_transform(df[[close]].values)对于股票数据我推荐用MinMaxScaler因为股票价格没有负值而且MinMaxScaler在反归一化时更直观预测结果能直接转换回真实价格。StandardScaler在做对比实验时也可以试一试但在报告中要说明两种方法的差异。注意这里的Scaler必须只在训练集上fit然后用同一个Scaler去transform测试集严禁在整个数据集上fit。否则会造成数据泄漏测试集的分布信息提前混进了训练过程实验结果虚高这在学术上是站不住脚的。3.3 滑窗机制构造有监督学习样本LSTM不能直接吃一长串股价序列需要把序列切割成“输入样本-标签”对。假设我们用过去look_back60天的数据预测下一天的价格具体做法是把数据做成X[0] [t0, t1, ..., t59] - y[0] t60 X[1] [t1, t2, ..., t60] - y[1] t61 ...def create_sequences(data, look_back60): X, y [], [] for i in range(len(data) - look_back): X.append(data[i:ilook_back, 0]) y.append(data[ilook_back, 0]) return np.array(X), np.array(y) look_back 60 X, y create_sequences(scaled_data, look_back) print(fX shape: {X.shape}, y shape: {y.shape})look_back是超参数中非常关键的一个。太小比如5天模型只看得到短期波动学不到中期趋势太大比如250天约一年交易日训练数据的长度会不够而且引入了太多历史噪声。我实测下来60约三个月交易日是一个不错的平衡点。但你完全可以在报告里做一个look_back敏感性分析每次改参数重新训练画N张预测图对比这种踏实劲导师不可能不给分。3.4 数据集切分训练集/验证集/测试集的划分原则时间序列数据的划分和普通机器学习数据不一样不能随机打乱必须按时间顺序划分否则就破坏了时间相关性相当于作弊。我采用的划分方式是前80%做训练集中间10%做验证集最后10%做测试集。train_size int(len(X) * 0.8) val_size int(len(X) * 0.1) X_train, y_train X[:train_size], y[:train_size] X_val, y_val X[train_size:train_sizeval_size], y[train_size:train_sizeval_size] X_test, y_test X[train_sizeval_size:], y[train_sizeval_size:] # 调整shape为LSTM输入格式(样本数, 时间步长, 特征数) X_train X_train.reshape((X_train.shape[0], X_train.shape[1], 1)) X_val X_val.reshape((X_val.shape[0], X_val.shape[1], 1)) X_test X_test.reshape((X_test.shape[0], X_test.shape[1], 1))这里有一个容易被忽略的细节——只用收盘价做特征还是加入其它特征只用收盘价模型学到的模式相对有限但思路清晰便于解释。如果你想拿更高的分可以尝试加入开盘价、最高价、最低价、成交量甚至是一些技术指标如MACD、RSI。特征多了模型输入维度从1变成N需要调整模型结构但报告的内容会更丰富。我当时报告里做了一个对比“单特征 vs 多特征”多特征模型的RMSE略高即更准但训练时间多了将近一倍。这个实验极大的丰富了报告的深度帮你拉开和同班同学的差距。4. LSTM模型设计与训练调优4.1 网络结构设计如何确定层数和神经元数量LSTM网络的结构设计是整个项目的核心环节。我的目标是要在“表达能力”和“过拟合风险”之间找到平衡点。一个标准的LSTM回归模型长这样import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.optimizers import Adam from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau def build_lstm_model(look_back60, n_features1): model Sequential([ LSTM(units128, return_sequencesTrue, input_shape(look_back, n_features)), Dropout(0.2), LSTM(units64, return_sequencesFalse), Dropout(0.2), Dense(units32, activationrelu), Dense(units1) ]) model.compile(optimizerAdam(learning_rate0.001), lossmean_squared_error, metrics[mae]) return model model build_lstm_model() model.summary()结构的关键点第一层LSTM需要return_sequencesTrue因为要输出完整的序列到下一层LSTMDropout层防止过拟合0.2的含义是在训练时随机丢弃20%的神经元连接最后一层是Dense(1)因为我们要输出一个连续值下一天的股价不是分类所以没有激活函数损失函数用MSE因为这个任务本质是回归问题MSE对大的预测误差敏感能有效指导模型优化关于神经元数量没有绝对的公式但有一个经验法则输入特征的8~16倍。单特征下用32~128都合理。神经元翻倍计算量会翻4倍因为LSTM的矩阵乘法是输入维度和单元数同时影响参数量所以不要盲目选大的。4.2 训练参数的配置与理由训练的核心参数包括batch size、epochs、学习率和早停机制。我推荐的配置如下batch size 64比较中庸的选择在训练速度和梯度稳定性之间折中。太大如256会让梯度方向过于“平均”错过最优解太小如16训练不稳定、震荡大epochs 100训练100轮同时配合早停learning rate 0.001Adam优化器的默认学习率通常不需要动EarlyStopping patience15如果验证集loss连续15个epoch没有下降就提前停止防止过拟合early_stopping EarlyStopping(monitorval_loss, patience15, restore_best_weightsTrue) reduce_lr ReduceLROnPlateau(monitorval_loss, factor0.5, patience5, min_lr1e-6) history model.fit( X_train, y_train, validation_data(X_val, y_val), epochs100, batch_size64, callbacks[early_stopping, reduce_lr], verbose1 )ReduceLROnPlateau是个很实用的调参技巧。当验证损失进入平台期学习率自动减半让模型在小步长下继续精细搜索。这个细节写进报告里能显得你很懂调参。4.3 训练过程中的损失曲线解读训练完成后第一件事就是画损失曲线。这是报告中最基础也是最重要的图之一。import matplotlib.pyplot as plt plt.figure(figsize(12, 5)) plt.plot(history.history[loss], labelTraining Loss) plt.plot(history.history[val_loss], labelValidation Loss) plt.title(Model Loss) plt.xlabel(Epochs) plt.ylabel(Loss) plt.legend() plt.savefig(figures/loss_curve.png, dpi300, bbox_inchestight) plt.show()那到底怎么解读这张图呢如果训练损失和验证损失都持续下降并趋于平稳说明模型健康没有过拟合如果训练损失还在下降但验证损失已经开始上升说明过拟合了需要加大Dropout、减小模型规模、或者增加早停的力度如果两条曲线都不降或者震荡得非常厉害说明学习率可能太高或者数据归一化没做好我当时训练到第50轮左右早停就触发了模型恢复到了best weights。整个训练过程不到3分钟GTX 1660显卡CPU也不慢。这个训练成本对学生党很友好。4.4 预测与反归一化训练完成后做预测注意一个细节预测时也要做滑窗不能一次性把整个测试集丢进去那是作弊。需要像“滚动预测”一样用已知的真实数据点逐个生成预测结果。不过为了简单且有效大部分期末作业的做法是一次性把测试集X_test丢进模型得到每个样本点的预测序列再反归一化回真实股价。我这个阶段也是这么做的。如果你追求更高阶的玩法可以尝试“多步递归预测”预测出下一天的股价后把预测值拼进输入序列继续迭代预测未来5天。这样更像真实的交易场景但误差会累积。# 模型预测 predicted_prices model.predict(X_test) # 反归一化把预测值和真实值都还原到原始价格尺度 predicted_prices scaler.inverse_transform(predicted_prices.reshape(-1, 1)) real_prices scaler.inverse_transform(y_test.reshape(-1, 1))值得说明的是scaler.inverse_transform的输入必须和fit时的shape一致所以这里都会reshape(-1, 1)一下。这个细节在报告里可以提一下因为很多同学代码报错就在这种小地方。5. 评估指标与结果可视化5.1 回归预测的核心指标MAE、RMSE、MAPE评估模型性能时最常用的三个指标是MAE平均绝对误差误差绝对值的均值直观反映平均偏差多少“元”RMSE均方根误差误差平方的均值的开方对大误差更敏感能放大模型在某些极端点上的失误MAPE平均绝对百分比误差误差占真实值的百分比可以说是最直观的指标衡量误差的相对大小from sklearn.metrics import mean_absolute_error, mean_squared_error import numpy as np mae mean_absolute_error(real_prices, predicted_prices) rmse np.sqrt(mean_squared_error(real_prices, predicted_prices)) mape np.mean(np.abs((real_prices - predicted_prices) / real_prices)) * 100 print(fMAE: {mae:.4f}) print(fRMSE: {rmse:.4f}) print(fMAPE: {mape:.2f}%)打个比方假设平安银行股价在10~15元之间波动模型算出来的RMSE如果是0.3元MAPE大概是2%上下这意味着平均每次预测误差只有两三毛钱精度已经很不错了。如果你计算出MAPE在1%以内那这个模型足以惊艳大多数评分老师。5.2 可视化结果如何画一张能“讲出故事”的图预测曲线和真实曲线的对比图是整份报告的灵魂。这张图画得好不好直接影响观感。plt.figure(figsize(16, 6)) # 划分绘图区间训练集/测试集 train_predict_dates df[date].values[look_back:look_backlen(X_train)] val_predict_dates df[date].values[look_backlen(X_train):look_backlen(X_train)len(X_val)] test_predict_dates df[date].values[look_backlen(X_train)len(X_val):] # 绘制真实价格曲线 plt.plot(test_predict_dates, real_prices, labelReal Price, color#1f77b4, linewidth2) # 绘制预测价格曲线 plt.plot(test_predict_dates, predicted_prices, labelPredicted Price, color#ff7f0e, linewidth2, linestyle--) plt.title(LSTM Stock Price Prediction - Test Set, fontsize16) plt.xlabel(Date, fontsize12) plt.ylabel(Price (CNY), fontsize12) plt.legend() plt.grid(True, alpha0.3) plt.xticks(rotation45) plt.tight_layout() plt.savefig(figures/prediction_result.png, dpi300, bbox_inchestight) plt.show()在报告里对这张图的解读应该是模型的预测曲线橙色虚线和真实曲线蓝色实线走势基本一致模型成功捕捉到了从上行到下行的趋势转折点但在局部高峰和低谷处存在一定滞后这是LSTM模型基于历史数据滚动预测的固有特性。有一说一这句话写到报告里比单纯贴一张图有说服力一百倍。5.3 误差分布分析除了预测-真实曲线建议再加一张误差分布图这会让你的报告在“分析深度”上远超同学errors (real_prices - predicted_prices).flatten() plt.figure(figsize(12, 4)) plt.subplot(1, 2, 1) plt.hist(errors, bins30, edgecolorblack, alpha0.7) plt.title(Prediction Error Distribution) plt.xlabel(Error (CNY)) plt.ylabel(Frequency) plt.subplot(1, 2, 2) plt.plot(errors) plt.title(Error Sequence Over Time) plt.xlabel(Sample Index) plt.ylabel(Error (CNY)) plt.tight_layout() plt.savefig(figures/error_analysis.png, dpi300) plt.show()误差基本围绕0值对称分布说明模型没有系统性偏差误差随时间的变化没有明显的模式说明误差是随机的模型能力已经在当前特征和结构下得到了充分挖掘。6. 常见问题与排查技巧实录6.1 典型报错维度不匹配在调整数据shape、输入模型时最容易遇到维度错误ValueError: Input 0 of layer lstm is incompatible with the layer: expected ndim3, found ndim2. Full shape received: (None, 60)原因LSTM层期望三维输入(batch_size, time_steps, features)但传进去的X_train是二维的说明忘了reshape。解决办法就是上面代码里那行X_train X_train.reshape((X_train.shape[0], X_train.shape[1], 1))6.2 训练损失不下降或震荡原因可能有三个数据没有归一化或归一化方式不对比如fit和transform混在一起学习率过大从0.01改成0.001试试数据量太少模型无法拟合增加历史数据的时间范围从3年加到5年6.3 预测结果是一条“平移的线”完全滞后于真实曲线这是LSTM做股票预测时最经典的现象。模型学到的规律往往是“今天的股价≈昨天的股价”所以预测结果看起来像真实曲线整体向右平移了一天。出现这种情况说明模型没有学到真正的趋势模式只是在拟合一个“惯性”。解决思路调整look_back拉长历史视野加入更多特征成交量、开盘价、最高价、最低价让模型有更多信息可用尝试差分处理预测的不是价格本身而是价格的变化量明天的价格减去今天的价格6.4 安装TensorFlow失败如果在Windows上安装TensorFlow遇到Failed to load the native TensorFlow runtime大概率是Visual C运行库没装去官网下载“Visual C Redistributable”安装即可。如果遇到No module named tensorflow检查当前环境的pip是否指向了正确路径pip list | grep tensorflow python -c import tensorflow as tf; print(tf.__version__)6.5 反归一化后的预测值出现负值预测出的价格变成负数明显不合理但反归一化之后确实可能遇到因为模型在极端情况下可能输出负值。解决办法加一层ReLU或abs或者在评估时直接忽略这种异常值也可以用numpy.clip把预测值clip到最低0。7. 冲95分以上的报告撰写技巧与后续扩展7.1 报告结构与篇幅分配一份高分报告结构应该严格遵循学术论文的规范摘要300字以内说清楚研究目标、方法、主要结果引言200-500字说明研究背景和意义相关工作/理论基础500-800字解释LSTM的原理配上门控结构的示意图数据与预处理500-800字来源、范围、归一化、滑窗模型设计500-800字结构图、参数表、超参数选择理由实验结果与分析800-1200字指标表、预测图、误差分析、对比实验总结与展望300字以内说清模型局限性参考文献至少8-10篇其中结果分析部分是最能拉分的。单纯把指标列出来不算分析你要讨论“为什么RMSE偏高”、“哪个时间段预测效果差、为什么”、“如果换一只股票结果会怎样”。7.2 对比实验如果想让分数突破95建议加一个对比模型。最简单的做法是用sklearn的线性回归或者支持向量回归跑同样的数据对比RMSE、MAPE。这么做的意义在于展示了你的批判性思维LSTM不一定在所有场景下都比传统模型好你能客观分析优劣这就是研究能力。7.3 后续可以怎么玩如果你拿了95分还想继续深化方向很多用注意力机制改造LSTM、用Transformer/Informer做时间序列预测、做多因子选股、搭建一个自动交易的回测框架。期末作业不是终点它是你入门“AI金融”的第一步。7.4 关于“代码复用”和“防止千篇一律”的最后提醒基于LSTM的股票预测是全网教程最多的Python项目之一。如果你照着别人的代码改个股票代码就交上去大概率会和同学撞车甚至被老师看出是模板。高分的前提是你能讲清每一步为什么这么做加入自己的实验体现出自己的思考。换句话说代码可以借鉴但报告里的深度、图表、对比分析都应该是你自己亲手产出的。我个人在实际操作中的体会是这个项目的难点其实不在LSTM本身而是在于各项细节的把控。数据是否规范、归一化是否泄露、滑窗大小是否有依据、指标解读是否到位每一个细节差一点总分就拉开了10分。把这份复盘里的每一个坑都避开你的期末大作业就已经站在了优秀线上。本文还有配套的精品资源点击获取