基于机器学习的股票预测方法研究:从特征工程到时间序列验证
2026/9/24 10:57:10 网站建设 项目流程

简介:这是一份基于机器学习的股票预测方法研究的论文文档,格式为docx,专为毕业设计、课程设计论文写作提供参考。内容系统梳理了股市预测两类主流方法:其一仅利用历史股票数据,涵盖分段线性表示、高斯过程分类、随机森林、支持向量机、卷积神经网络、长短期记忆网络、生成对抗网络等经典与深度模型;其二引入金融新闻、社交媒体股民评论等非结构化文本,通过事件结构化表示、情感极性分析等方式提升预测效果。全文从引言、方法综述到总结展望层层展开,写作规范、逻辑紧密,适合初学者、工程师、在校师生及毕业生借鉴学习。资源包共1个docx文件,大小约35KB,虽体积小巧,但包含了摘要、关键词、细分方法对比与结论等完整论文结构。已有586人浏览学习,可用于毕业论文或课程设计的重要参考,建议仔细研读其中的知识点、方法脉络与实验思路,切勿直接照抄。

1. 这个标题真正要你做的东西:不止是预测涨跌

如果你在找《基于机器学习的股票预测方法研究》这个题目的资料,大概率是正在写本科毕设、课程设计或者期末大作业。第一个需要认清的事实是:这个题目的价值不在「预测准确率有多高」,而在于你能不能给出一个完整、闭环、经得起答辩老师追问的研究过程。我见过太多人一上来就调 LSTM,最后发现把数据随机打乱之后模型"神准",却在按时间顺序回测时被现实打脸。

这篇文章会按照我实际带学生做这类题目的顺序来讲:先处理数据和特征,再选模型,再做严格的时间序列验证,最后说清楚论文里哪些地方最容易暴露问题。全程围绕机器学习做股票预测的最小可行路线,不吹玄学,不承诺收益,只保证你每一步都有代码、有参数、有可复现的结果。明确一点:你做的是研究性项目,不是量化交易系统,评价标准是方法正确、实验严谨、结论可信,而不是"赚了多少钱"。

2. 样本和特征怎么造:做预测之前先回答一个问题

2.1 原始数据拿到手,先别急着建模

股票预测本质上是时间序列预测,我们面对的不是一串独立样本,而是一根根按时间排列的K线。绝大多数新手翻车的第一步,就是把股票数据当成普通表格数据,随手一读就开始训练。后面第五章会专门说这个坑,但这里要先建立正确的数据观。

常见的做法是用 Python 的 pandas 直接读取日线数据,一般包含这些字段:date、open、high、low、close、volume。这类数据在网上很多,不管是免费的证券接口还是金融数据网站,格式大同小异。你需要关心的不是获取渠道,而是字段含义和采样频率。主流的毕设选题用日线就够了,分钟线数据量太大且噪声更多,不好控制实验。

数据准备的第一步是排序和清洗。排序很好理解,时间序列必须按日期升序排列,这点尤其重要,因为后面要按位置切分训练集和测试集。清洗主要是处理除权导致的股价跳空。这个细节几乎每个学生都会遇到,股票分红送股后价格会瞬间低开,直接读取会让模型产生一个"暴跌"的假象。

import pandas as pd df = pd.read_csv('stock_daily.csv') df['date'] = pd.to_datetime(df['date']) df = df.sort_values('date').reset_index(drop=True) # 用前复权方式调整价格,q 是复权因子,不同数据源字段不同 df['close_adj'] = df['close'] * df['q'] df['open_adj'] = df['open'] * df['q'] df = df.dropna(subset=['close_adj'])

这里的核心逻辑是:复权后的价格序列才能真实反映连续的价格变化,模型学到的才不是除权缺口。参数上,dropna 处理停牌缺失;如果你拿到的数据源已经复权,那这一步可以直接跳过。我一般会先画一张价格曲线图,一眼看出有没有异常跳空。

2.2 特征工程:滞后特征是主角,未来函数是红线

特征构造是机器学习股票预测里最体现工作量、最容易得分、也最容易被答辩老师挑刺的环节。定义很清晰:我们要用 t 日以及 t 日之前的信息预测 t+1 日的涨跌,任何用到未来信息的特征都叫未来函数,一旦出现,整个实验结果作废。

常用特征分几大类:直接来自行情的基础特征、由基础特征推导的技术指标、以及收益率序列的统计量。基础特征很简单,比如开盘价、收盘价、成交量;技术指标库很多,talib 是个常见选择,但毕设里我更建议用 pandas 手写几个核心指标,因为答辩老师问起公式时你答得上来。

# 收益率:当前收盘相对于前一日收盘的涨跌幅 df['ret_1'] = df['close_adj'].pct_change() # 5日和20日均线 df['ma5'] = df['close_adj'].rolling(5).mean() df['ma20'] = df['close_adj'].rolling(20).mean() # 动量:过去5日累计涨幅 df['mom5'] = df['close_adj'] / df['close_adj'].shift(5) - 1 # 波动率:过去20日日收益率的标准差 df['vol20'] = df['ret_1'].rolling(20).std() # 标签:下一交易日是否上涨,用shift(-1)取未来数据 df['label_up'] = (df['close_adj'].shift(-1) > df['close_adj']).astype(int) df = df.replace([float('inf'), -float('inf')], float('nan')) df = df.dropna()

三个关键点。第一,所有特征要么用 rolling 窗口,要么用 shift 做滞后对齐,确保 t 时刻的特征只含 t 及之前的信息。第二,label 用 shift(-1) 取的是未来,但标签本身不算特征泄漏,因为标签就是你要预测的目标。第三,pct_change 和除法会制造无穷大,必须处理,不然模型直接崩。每个特征之间实际上高度相关,但树模型和线性模型对这个没那么敏感,后面模型章节会展开。

2.3 训练集测试集怎么切:按时间顺序切,而不是随机切

数据准备好之后就是划分数据集。普通机器学习里用 train_test_split 随机划分是标准操作,但股票数据绝不能这么做。原因很直接:股票数据是串行相关的,今天的股价和昨天高度相关,随机划分会让模型看到"未来"片段,测试集就成了开卷考试。

train_size = int(len(df) * 0.7) train_df = df.iloc[:train_size] test_df = df.iloc[train_size:] feature_cols = ['ret_1', 'ma5', 'ma20', 'mom5', 'vol20'] X_train = train_df[feature_cols] y_train = train_df['label_up'] X_test = test_df[feature_cols] y_test = test_df['label_up']

按时间顺序切分的好处是贴近真实场景:用 70% 的历史数据训练,然后在剩余 30% 的未来数据上验证。导师问起来,你这个逻辑完全站得住。参数上,70/30 是常见比例,数据量少时可以用 80/20;时间跨度上最好把不同市场环境(上涨段、下跌段、震荡段)都包含进去,否则模型只见过牛市,测试集全是熊市,结果没有说服力。

3. 模型选型:从线性回归到 LSTM,每一层都要能讲清理由

3.1 先跑通线性回归:一个表现意外不错的基础线

选模型之前先定性能基准,这是机器学习项目里最基本的工程习惯。线性回归的好处是简单、可解释、几乎不会跑崩,而且对"预测下一日涨跌"这类弱信号问题,线性模型往往不比复杂模型差太多。

from sklearn.linear_model import LinearRegression, LogisticRegression from sklearn.metrics import accuracy_score, mean_squared_error # 回归版本:预测收益率数值 reg = LinearRegression() reg.fit(X_train, train_df['ret_1'].shift(-1).dropna()[:len(X_train)]) y_pred_reg = reg.predict(X_test) mse = mean_squared_error(test_df['ret_1'].shift(-1).dropna()[:len(y_pred_reg)], y_pred_reg) print('线性回归 MSE:', mse)

这里说的逻辑是:线性回归拟合的是"特征到未来收益率的线性映射",它的系数代表每个特征的边际影响,可以直接写进论文做解释。参数上没什么需要调的,但要注意 X 和 y 的长度对齐,shift(-1) 会造成最后一个样本的标签为空,这点必须处理干净。MSE 作为评价指标是有问题的,第五章会专门展开。

既然任务是涨跌分类,那更自然的选择是逻辑回归。它的输出是上涨概率,阈值取 0.5 的时候刚好对应二分类,论文里也更好写——你预测的不是"涨多少",而是"涨的概率有多大"。

from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_train_s = scaler.fit_transform(X_train) X_test_s = scaler.transform(X_test) clf = LogisticRegression(C=1.0, max_iter=1000) clf.fit(X_train_s, y_train) y_pred = clf.predict(X_test_s) y_proba = clf.predict_proba(X_test_s)[:, 1] print('逻辑回归准确率:', accuracy_score(y_test, y_pred))

逻辑回归这里有两个参数值得讲。C 是正则化强度的倒数,C 越小正则化越强,默认 1.0 一般够用,特征多或者共线性严重时可以调到 0.1 试试;max_iter 设到 1000 是为了让模型收敛,特征标准化后这个问题通常不明显。StandardScaler 对逻辑回归很重要,因为正则化惩罚项的尺度受特征量纲影响,不标准化的话均线和收益率这种数值差异巨大的特征会被正则化扭曲。

3.2 树模型和梯度提升:竞赛首选但在股票数据上要克制

梯度提升树(GBDT)是机器学习表格数据上的常胜将军,XGBoost、LightGBM 在各类比赛里几乎统治了结构化数据任务。股票特征以表格形式存在,所以树模型自然是必试方案。但你在论文里需要说清楚:为什么选树模型,为什么结果可能不如预期。

随机森林直接集成多棵决策树,对特征量纲不敏感,不需要标准化,能捕捉特征之间的非线性关系;梯度提升则是串行训练弱学习器,每棵树纠正前一棵树的残差。从实现角度,XGBoost 或者 sklearn 的 GradientBoostingClassifier 都行,毕设用哪个取决于安装环境,sklearn 不用额外装包,演示成本最低。

from sklearn.ensemble import GradientBoostingClassifier gbdt = GradientBoostingClassifier( n_estimators=100, max_depth=3, learning_rate=0.1, subsample=0.8, random_state=42 ) gbdt.fit(X_train, y_train) y_pred_gbdt = gbdt.predict(X_test) print('GBDT 准确率:', accuracy_score(y_test, y_pred_gbdt)) print('特征重要度:', dict(zip(feature_cols, gbdt.feature_importances_)))

三个参数值得写进论文。n_estimators 是树的数量,100 是个起点,树太多容易过拟合;max_depth 是树的深度,3 到 5 是股票数据的合理区间,太深会把噪声都记住;learning_rate 是学习率,0.1 比较保守,配合 n_estimators 一起调——学习率越小,需要越多树。subsample 是随机采样比例,0.8 表示每棵树只用 80% 的样本,这本身就是防止过拟合的手段。

树模型能输出特征重要性,这是它相比神经网络的巨大优势。答辩时老师问"你的模型学到了什么",你可以直接回答:过去5日动量最重要、波动率次之、均线类特征最弱。这种回答比空谈准确率有说服力得多。

3.3 深度学习模型:能写但别指望翻盘

LSTM 在时间序列预测里被提到最多,几乎每个股票预测相关的毕设都会想用它。实际结论可能会让很多学生失望:在日线数据、手工特征这个设定下,LSTM 很难稳定超过调好的 GBDT,尤其是当你的样本量只有几百条的时候。但你依然可以把它作为对比模型写进论文,证明你做了充分调研,这个姿态本身就有价值。

import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout # 构造时间窗口样本,用过去20天的特征序列预测明日涨跌 def make_sequences(features, labels, seq_len=20): X, y = [], [] for i in range(seq_len, len(features)): X.append(features[i - seq_len:i]) y.append(labels[i]) return np.array(X), np.array(y) X_seq, y_seq = make_sequences(X_train_s.values, y_train.values) X_test_seq, y_test_seq = make_sequences(X_test_s.values, y_test.values) model = Sequential() model.add(LSTM(32, input_shape=(X_seq.shape[1], X_seq.shape[2]), return_sequences=True)) model.add(Dropout(0.2)) model.add(LSTM(16)) model.add(Dense(1, activation='sigmoid')) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

LSTM 的 input_shape 是(时间步长、特征数),时间步长 20 天是经验值,代表模型看一个月的走势来做预测。Dropout 0.2 是防止循环神经网络在数据量小的时候严重过拟合。隐藏单元 32 和 16 是出于控制参数量的考虑,这个规模的数据集用不了更大的网络。编译这里用 sigmoid 做二分类输出,损失函数用 binary_crossentropy,这个组合与逻辑回归是一脉相承的。

3.4 模型对比的呈现方式:不只比准确率

论文里的模型对比表格,直接决定答辩老师对你工作量的判断。不要只放一个准确率列,至少要有这几个指标:准确率、F1-score、召回率、在上涨样本上的召回率。尤其最后一项——如果模型把所有样本都预测为"跌",准确率可能也不低,但明显没有研究价值。

模型准确率F1上涨样本召回率上涨样本精确率
逻辑回归????
GBDT????
LSTM????

这里建议用测试集的预测结果填充这个表,并写一小段分析:哪个模型在哪个指标上占优、为什么。比如 LSTM 的准确率可能略低,但对上涨样本的召回率更高,这在"宁可错过,不可误判"的场景下是另一个维度的能力。这种表格本身就是论文第三章或第四章的现成素材。

4. 评估和回测:预测对了方向,不等于能赚到钱

4.1 方向准确率和连续收益曲线才是有效信号

准确率这个指标在股票预测里非常容易误导人。如果行情整体下跌,测试期里下跌天数占多数,一个"永远预测跌"的模型可能拿到 52% 的准确率,看起来比随机猜测高一点,实际毫无价值。所以方向准确率要拆开看:上涨预测对了多少、下跌预测对了多少,以及最重要的——方向准确率是否稳定超过 50%。

回测的意义是把预测结果转化成"如果按照这个预测去买卖,收益曲线长什么样"。那是一个很标准的实验:

import numpy as np # 策略:预测上涨就持有,预测下跌就空仓 positions = np.where(y_pred_gbdt == 1, 1, 0) daily_ret = test_df['ret_1'].values[:len(positions)] strategy_ret = positions * daily_ret cumulative_strategy = np.cumprod(1 + strategy_ret) cumulative_benchmark = np.cumprod(1 + daily_ret) alpha = cumulative_strategy[-1] - cumulative_benchmark[-1]

核心逻辑是:基准是买入持有策略,策略收益是模型预测驱动。这里的平仓方式是"下跌预测时空仓",收益为 0;如果把做空机制加进来会复杂很多,毕设阶段不建议碰。alpha 是策略累计收益与基准累计收益的差,正 alpha 说明模型有增量价值。注意收益率序列要对齐 positions 的长度,标签 shift 造成的错位非常隐蔽。

4.2 前推验证:比单次切分更有说服力的实验设计

70/30 的单次切分只能说明模型在某一时段有效,答辩老师要是问"换一段行情还行不行",你就需要更扎实的验证方案。常见做法是滚动前推验证,也叫时间序列交叉验证,sklearn 提供了现成工具。

from sklearn.model_selection import TimeSeriesSplit tscv = TimeSeriesSplit(n_splits=4) acc_list = [] for train_idx, val_idx in tscv.split(X_train_s): X_tr, X_val = X_train_s[train_idx], X_train_s[val_idx] y_tr, y_val = y_train.iloc[train_idx], y_train.iloc[val_idx] clf = LogisticRegression(C=1.0, max_iter=1000) clf.fit(X_tr, y_tr) acc = accuracy_score(y_val, clf.predict(X_val)) acc_list.append(acc) print('各折准确率:', acc_list) print('平均准确率:', np.mean(acc_list))

TimeSeriesSplit 的做法是:第 1 折用前 25% 训练、下一段验证,第 2 折用前 50% 训练、再下一段验证,依此类推。这样每一折的测试段都在训练段之后,不存在未来信息。这四个准确率如果都在 50% 附近波动,说明模型不稳定,你的结论要如实写"在特定市场环境下具有弱预测能力",而不是硬说模型好。这个验证逻辑是你论文里实验设计部分的亮点,大多数学生想不到这一步。

4.3 损失函数角度理解为什么预测难

从机器学习角度看,股票预测难是因为信号弱、噪声强。y 的方差大部分来自无法预测的随机成分,模型能解释的部分占比很低。这反映在损失函数上就是:不管你怎么调参,损失下降都是平缓的,验证集损失很容易反弹。

所以我的建议是:论文里不要回避这个问题,直接写"用均方误差作为回归损失时,模型倾向预测接近 0 的收益率",这就是弱信号问题的直观体现。逻辑上转折到分类问题上,用涨跌分类替代回归,是这类研究的标准取舍。这种分析在最终论文里反而成为加分项,评阅人会认为"他真的理解了自己做的东西"。

5. 避坑与常见问题排查:论文翻车的五个高发点

5.1 未来函数:特征悄悄用了未来数据

现象是:训练时模型表现极好,测试时说不通地差。原因是特征或者标签对齐出了问题。最常见的场景是计算均线时忘记用 shift、做滚动回归时窗口跨越了样本点、或者对全序列做了标准化后再切分——标准化这个操作本身就用了全序列的均值方差,属于隐性未来信息。

解决的办法是:自检每一条特征构造代码,确认只用到了当根K线以及之前的信息;标准化只能先 fit 训练集,再用训练集的参数 transform 测试集。我建议在写完特征后,打印一条特征序列和原始数据的对比,看一眼第 t 行的值到底由哪些日期的数据算出,这一步就能过滤掉九成未来函数。

5.2 用回归预测股价数值,结果差到怀疑人生

现象是:预测的"明日价格"和真实价格曲线严重偏离,甚至预测值长期停留在某个均值附近。原因是价格序列的非平稳性——今天的价格和 20 天前的价格高度相关,回归模型学到的其实是"价格等于上一日价格"这种平庸解。

解决的办法是预测收益率而不是预测价格。收益率是平稳序列,可预测性和可解释性都更好;预测出收益率后,要用策略回测来判断价值,而不是看价格曲线贴得有多近。这是这个方向上必须树立的最基本的建模观念。

5.3 类别不平衡导致模型只会说"跌"

现象是:测试集上模型预测几乎全为 0(下跌),准确率却不算太低。原因是下跌天数占比约 55% 到 60%,逻辑回归在默认阈值下为了最小化损失,倾向预测多数类。

解决的办法有三个层级。第一,看混淆矩阵,别只看 accuracy;第二,用 class_weight='balanced' 让少数类获得更高的错分惩罚;第三,调整预测阈值,比如只预测上涨概率大于 0.6 时才判为上涨,虽然参与交易的次数变少,但单次判断的可靠性提高。这在论文里写清楚,是很成熟的实验改进思路。

5.4 标准化时机错误:测试集信息提前泄露

现象是:模型训练结果好得异常,但按时间顺序回测却一塌糊涂。原因极可能是对训练集和测试集合并后做了标准化。StandardScaler 的 fit 会在全量数据上计算均值和方差,测试集的分布信息因此被模型间接看到。

解决的办法是先把数据按时间切分,再在训练集上 fit scaler、用同一组参数 transform 测试集。代码结构上,切分数据和特征工程最好是两个函数,训练流程里先切分再进 pipeline,这样答辩时逻辑也好讲。

5.5 数据量不足以支撑 LSTM,但论文里硬写

现象是:LSTM 的准确率比随机猜测还低,训练集上却接近 100%。原因是样本只有几百根日线,LSTM 参数量远大于样本量,记住训练集易如反掌,泛化无从谈起。

解决的办法是:要么增加数据频度,用更长历史区间的日线;要么用滑动窗口构造更多样本,让序列截取数量增加到几千条;要么诚实承认数据量的边界,把 LSTM 作为探讨性实验。这几年毕设答辩老师对"滥用深度学习"基本零容忍,诚实反而安全。

6. 从预测到论文:让实验结论站稳的三个细节

数据和实验做完后,论文的呈现方式同样决定成败。先说图表:至少要画三张图,特征相关性热力图、测试集预测概率分布图、策略累计收益曲线对比图。收益曲线对比图里画两条线,一条是买入持有基准,一条是模型策略,肉眼可见的差距比任何统计指标都有冲击力。特征相关性热力图则能证明你对自己用到的特征做了充分了解。

再一个细节是特征的滞后阶数。答辩老师经常问"为什么用 5 日均线和 20 日均线,不用 10 日和 30 日"。我的习惯是做一个小实验:把特征窗口参数改成几组不同值,跑一遍对比准确率,把结果放进附录。这不花多少时间,但能显示出你在参数选择上是有实验依据的,而不是随手填的。除此之外,每个模型的参数表最好整理成一个统一表格,写上参数名、取值、调整后效果,这会让论文的"实验设计"部分像模像样。

最后说说机器学习本身基本功的问题。这类论文答辩时,老师很可能不会深究你的模型原理细节,但一定会问一个所有机器学习任务都逃不开的问题:你的模型有没有欠拟合或过拟合,你是怎么看出来的。你要能用一句话回答:训练集准确率远高于测试集是过拟合,两者都低是欠拟合,中间的标准是正则化项调参和验证曲线。建议去做一套小数据上的验证曲线实验,横轴是树的深度或者正则化强度,纵轴是训练集和测试集各自得分,这个图放论文里,任何答辩老师看了都会认可你的工程素养。

做这个题目最深的体会是:股票预测方向的研究性工作,功夫更多在数据逻辑和实验设计上,而不在模型本身。你要是把未来函数堵死、评估指标选对、对比实验做扎实,哪怕最终结论是"当前特征集下预测能力弱于随机水平",论文也能立得住。反之,模型再花哨,时序划分一塌糊涂,答辩现场必然露馅。希望这次梳理能帮你在毕设里少走弯路,把时间花在真正有价值的事情上。

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

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

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

立即咨询