☰
Python深度学习股票预测实战:从数据特征到模型评估的完整链路
2026/9/27 23:07:30 网站建设 项目流程

简介:这份Python期末大型作业资源聚焦深度学习在股票分析预测中的实战应用,面向计算机相关专业学生及希望积累项目经验的自学者,难度适中,适合作为课程设计或技能进阶的参考案例。压缩包共20个文件,约4.24MB,包含6个py源码文件、6张预测结果图、3个csv数据集以及txt、md说明文档等,源码覆盖数据下载、指标计算、模型训练、回测与策略等完整流程,图片直观展示预测效果,数据文件便于直接复现实验。目前已有76人学习下载。项目经导师指导并通过评审,获得98分,代码经过本地编译与严格调试,可运行性有保障。读者可从中掌握数据预处理、LSTM等模型设计、训练验证及MSE、RMSE评估指标的使用,理解防止过拟合的常用策略,并借助Python生态完成从数据到预测的闭环实践,适合作为深度学习与金融科技交叉方向的入门到进阶练习。

1. 从一份期末大作业说起:深度学习做股票预测到底靠不靠谱

每年到了期末,总有一批同学在群里问同一个问题:用 Python 加深度学习做股票分析预测,这个方向能不能撑起一份大型作业,能不能拿到高分。我前后帮人看过不下二十份这类项目,说实话,绝大多数翻车不是因为模型不够深,而是因为一开始就把问题想错了。股票价格是一组带噪声、非平稳、信噪比极低的时间序列,你拿 LSTM 硬拟合历史收盘价,训练集 loss 能降到小数点后四位,一到测试集就原形毕露。所以这份作业真正要交付的,不是「预测明天涨到多少」这种玄学结论,而是一套能自圆其说的完整链路:数据怎么来、特征怎么造、模型怎么选、结果怎么评估、界面怎么展示。它适合正在做 Python 期末大型作业、想拿高分又不想纯堆砌代码的本科生,也适合刚入门深度学习、想找一个完整项目练手的转行者。下面我按自己带人做这类项目的顺序,把整条路径拆开讲清楚,包括每一步的参数、坑和取舍。

2. 数据与特征工程:股票预测项目的成败八成在这里

2.1 为什么原始收盘价不能直接喂给模型

很多人拿到一份 CSV,第一反应是df['close']直接丢进 LSTM,然后抱怨模型学不到东西。问题出在两点。第一,收盘价是非平稳序列,均值和方差随时间漂移,模型在训练段学到的数值范围,到了测试段完全对不上。第二,单变量输入信息量太低,价格本身只是市场博弈的结果,不含任何解释性。常见做法是先做平稳化处理,再叠加多维度特征。平稳化最直接的是差分或对数收益率,log(price_t / price_{t-1})这种形式能把绝对价格转成相对变化,量纲统一,也更接近模型假设的分布。特征维度上,我一般会加成交量、换手率、振幅、均线偏离度这几类,它们和价格的相关性高,计算成本又低。

需要提醒的是,别一上来就堆几十个技术指标。特征越多,过拟合风险越大,而且很多指标之间高度共线,模型学到的权重没有解释意义。我的经验是控制在 8 到 15 个特征,每个都能说清楚它代表什么。

2.2 用 pandas 构造特征与标签的最小代码

下面这段是我常用的特征构造骨架,基于日线数据,输入是一份含 date、open、high、low、close、volume 的 DataFrame。

import pandas as pd import numpy as np def build_features(df, window=5): df = df.copy() df['date'] = pd.to_datetime(df['date']) df = df.sort_values('date').reset_index(drop=True) # 对数收益率,平稳化核心 df['ret'] = np.log(df['close'] / df['close'].shift(1)) # 振幅:当日高低差相对开盘 df['amplitude'] = (df['high'] - df['low']) / df['open'] # 量比:当日成交量与过去 window 日均量之比 df['vol_ratio'] = df['volume'] / df['volume'].rolling(window).mean() # 均线偏离度 df['ma5'] = df['close'].rolling(5).mean() df['ma_bias'] = (df['close'] - df['ma5']) / df['ma5'] # 标签:下一日收益率方向,1 为涨,0 为跌 df['label'] = (df['ret'].shift(-1) > 0).astype(int) df = df.dropna().reset_index(drop=True) return df data = pd.read_csv('stock_daily.csv') feat = build_features(data, window=5) print(feat[['date', 'ret', 'amplitude', 'vol_ratio', 'ma_bias', 'label']].head())

逻辑上,ret用 shift(1) 保证只用历史信息,label用 shift(-1) 取下一日方向,这是监督学习对齐的关键。参数window控制均线和量比的回看周期,日线数据一般取 5 或 10,取太大特征会滞后。dropna会砍掉开头几行和最后一行,这是正常的,别为了凑数据量去填充,填充会引入未来信息。

2.3 训练集测试集划分:时间序列不能随机切

这是血泪经验最多的地方。用train_test_split随机打乱,在股票数据上等于作弊,因为未来样本会混进训练集,测试指标虚高得离谱。正确做法是按时间顺序切,比如前 70% 做训练,后 30% 做测试,中间可以留一段验证集做早停。如果要做滚动回测,就用 expanding window,每次用截至 t 的数据训练,预测 t+1,然后窗口前移。代码上很简单:

split = int(len(feat) * 0.7) train = feat.iloc[:split] test = feat.iloc[split:] feature_cols = ['ret', 'amplitude', 'vol_ratio', 'ma_bias'] X_train = train[feature_cols].values y_train = train['label'].values X_test = test[feature_cols].values y_test = test['label'].values

注意特征列里不要放 close 这种绝对价格,否则模型会记住训练段的数值区间。划分比例 7:3 是常见起点,数据量少于 1000 条时建议 8:2,保证训练充分。

3. 模型选型与训练:LSTM、CNN 还是树模型,别盲目追深

3.1 三类主流方案的适用边界

期末作业里最常见的三种选择:LSTM 类循环网络、一维 CNN、以及 XGBoost/LightGBM 这类树模型。很多人觉得深度学习作业就必须用 LSTM,其实不然。树模型在中小规模表格特征上往往更强,训练快、调参少、可解释性好,作为 baseline 非常合适。一维 CNN 擅长捕捉局部时序模式,比如连续几天的量价配合形态,计算比 LSTM 快,梯度问题也少。LSTM 理论上能记长依赖,但股票数据的有效记忆长度通常很短,超过 20 个交易日的信息基本是噪声,所以 LSTM 的优势未必发挥得出来。

我的建议是:先跑一个 LightGBM 作为基准,记录准确率和 F1;再上 1D CNN 或 LSTM 做对比。作业里能呈现「多模型对比 + 选型理由」,比只堆一个复杂网络更容易拿高分,因为老师看的是你的分析能力,不是网络层数。

3.2 用 PyTorch 搭一个 1D CNN 分类器

下面是一个可直接跑的最小 CNN 结构,输入形状为 (batch, features, seq_len)。

import torch import torch.nn as nn class StockCNN(nn.Module): def __init__(self, n_features, seq_len): super().__init__() # 第一层卷积提取局部量价模式 self.conv1 = nn.Conv1d(n_features, 32, kernel_size=3, padding=1) self.bn1 = nn.BatchNorm1d(32) self.conv2 = nn.Conv1d(32, 64, kernel_size=3, padding=1) self.bn2 = nn.BatchNorm1d(64) self.pool = nn.AdaptiveAvgPool1d(1) self.fc = nn.Linear(64, 2) self.relu = nn.ReLU() self.dropout = nn.Dropout(0.3) def forward(self, x): x = self.relu(self.bn1(self.conv1(x))) x = self.relu(self.bn2(self.conv2(x))) x = self.pool(x).squeeze(-1) x = self.dropout(x) return self.fc(x)

n_features是你特征列的数量,seq_len是时间窗口长度,一般取 10 到 30。kernel_size=3表示每次看连续三天,想捕捉更长模式可以加到 5。BatchNorm 在时序任务里能稳定训练,Dropout 0.3 是防过拟合的常用值,数据量小可以加到 0.5。输出维度 2 对应涨跌二分类,如果做三分类(涨、平、跌)就改成 3。

3.3 训练循环与关键超参数

训练部分我一般写成滑动窗口采样,把序列切成 (样本数, 特征数, 窗口长度) 的张量。

def make_sequences(X, y, seq_len): xs, ys = [], [] for i in range(len(X) - seq_len): xs.append(X[i:i+seq_len].T) # 转置成 (features, seq_len) ys.append(y[i+seq_len]) return torch.tensor(xs, dtype=torch.float32), torch.tensor(ys, dtype=torch.long) seq_len = 20 Xtr, ytr = make_sequences(X_train, y_train, seq_len) Xte, yte = make_sequences(X_test, y_test, seq_len) model = StockCNN(n_features=Xtr.shape[1], seq_len=seq_len) opt = torch.optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4) criterion = nn.CrossEntropyLoss() for epoch in range(50): model.train() opt.zero_grad() out = model(Xtr) loss = criterion(out, ytr) loss.backward() opt.step() if epoch % 10 == 0: print(f'epoch {epoch}, loss {loss.item():.4f}')

lr=1e-3是 Adam 的稳妥起点,weight_decay=1e-4做 L2 正则,能明显压过拟合。seq_len=20对应约一个月交易日,是常见取值。训练轮数别死盯 50,要看验证集 loss,一旦验证 loss 连续几轮不降就停,这就是早停。股票数据上,模型往往几个 epoch 就收敛,继续训只会记住噪声。

4. 评估与可视化:准确率会骗人,别只看一个数

4.1 为什么准确率在股票任务里不可信

涨跌二分类里,如果样本本身涨跌比例是 55:45,模型全猜「涨」就有 55% 准确率。你辛苦训出来的网络如果只有 54%,还不如瞎猜。所以评估必须看多个指标:精确率、召回率、F1,以及混淆矩阵。更专业一点,可以算一下策略收益:按模型信号做多空,扣掉手续费后看累计收益曲线,这比分类指标更贴近实际意义。作业里能画出这条曲线,说服力会强很多。

4.2 混淆矩阵与分类报告的代码

from sklearn.metrics import classification_report, confusion_matrix import seaborn as sns import matplotlib.pyplot as plt model.eval() with torch.no_grad(): logits = model(Xte) pred = logits.argmax(dim=1).numpy() print(classification_report(yte.numpy(), pred, target_names=['跌', '涨'])) cm = confusion_matrix(yte.numpy(), pred) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=['跌', '涨'], yticklabels=['跌', '涨']) plt.xlabel('预测') plt.ylabel('真实') plt.savefig('confusion.png', dpi=150)

classification_report会给出每类的 precision、recall、f1,重点看涨跌两类是否均衡。如果模型只对某一类敏感,说明样本不均衡或特征有偏。混淆矩阵热力图适合放进作业报告,直观展示误判分布。保存图片用 dpi=150,打印和 PDF 都够清晰。

4.3 回测曲线:把预测转成可解释的收益

import numpy as np # 用测试段真实收益率乘以信号,1 为做多,0 为空仓 test_ret = test['ret'].values[seq_len:] signal = pred # 1 看涨,0 看跌 strategy_ret = np.where(signal == 1, test_ret, 0) cum_strategy = np.cumprod(1 + strategy_ret) cum_buy_hold = np.cumprod(1 + test_ret) plt.plot(cum_strategy, label='模型策略') plt.plot(cum_buy_hold, label='买入持有') plt.legend() plt.title('累计收益对比') plt.savefig('backtest.png', dpi=150)

这里用np.where把信号映射成持仓,看涨就吃当日收益,看跌就空仓。cumprod算累计净值。注意这只是简化回测,没扣手续费和滑点,作业里说明这一点反而显得严谨。如果模型策略曲线长期跑不赢买入持有,别硬吹,如实分析原因,比如震荡市里方向预测本身难度大。

5. 避坑与排查:这类项目最容易翻车的五个地方

5.1 未来函数混进特征

现象:测试集准确率异常高,超过 80%,但实盘逻辑说不通。原因:构造特征时用了 shift 方向错误,或者归一化时用了全量数据的均值方差。解决:所有特征只能用 t 时刻及之前的数据,标准化参数必须从训练集计算再应用到测试集。检查方法很简单,把特征和标签的时间戳打印出来,逐个核对。

5.2 标签泄漏

现象:训练 loss 极低,验证 loss 也低,但预测下一日方向完全随机。原因:标签构造时把当日信息带进去了,比如用当日收盘价判断当日涨跌再作为预测目标。解决:标签必须是「未来」的,用 shift(-1) 或 shift(-n),并确保特征窗口和标签之间没有重叠。

5.3 样本极度不均衡

现象:模型几乎全预测一个类别,F1 某一类为 0。原因:某些股票长期单边行情,涨跌样本比例悬殊。解决:用类别权重CrossEntropyLoss(weight=...),或者对少数类过采样。也可以换指标,用 AUC 代替准确率。

5.4 过拟合到具体股票

现象:在训练用的那只股票上表现好,换一只就崩。原因:模型记住了该股票的特定波动模式,泛化差。解决:训练时混入多只股票的数据,或者用行业指数做预训练。作业里如果只用一只股票,要在结论里明确说明适用范围有限。

5.5 环境与依赖版本冲突

现象:PyTorch 和 numpy 版本不匹配,报RuntimeError或ImportError。原因:深度学习环境配置是新手高频翻车点,pip 装了一堆包互相打架。解决:用 conda 建独立环境,先装 PyTorch 官方命令,再装 pandas、sklearn。记录一份 requirements.txt,方便复现。VS Code 里记得选对解释器,别用系统默认的。

6. 让作业加分的一个技巧:把预测结果做成可交互界面

代码跑通只是及格线,想拿高分得让老师一眼看到成果。我的习惯是用 Streamlit 或 Gradio 套一个简单界面,输入股票代码或上传 CSV,实时显示预测信号和收益曲线。Streamlit 上手最快,十几行就能出一个网页。

import streamlit as st import pandas as pd st.title('股票涨跌预测演示') uploaded = st.file_uploader('上传日线CSV', type='csv') if uploaded: df = pd.read_csv(uploaded) st.line_chart(df.set_index('date')['close']) st.write('模型预测:下一交易日看涨' if pred[-1] == 1 else '模型预测:下一交易日看跌')

file_uploader让用户自己传数据,line_chart画价格走势,最后一行输出模型信号。部署到本地streamlit run app.py就能看。界面不用花哨,能演示完整流程就行。老师看到你能把模型、数据、可视化串起来,印象分直接拉满。

最后说个我自己的习惯:每次做完这类项目,我都会把随机种子固定下来,torch.manual_seed(42)、np.random.seed(42),然后把完整运行日志存一份。因为股票数据每次划分、每次初始化权重结果都不一样,不固定种子,你自己都复现不了昨天的结果,更别说写进报告。这个习惯帮我省了无数次返工。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询