ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于sklearn的机器学习股票预测:特征工程与模型实战指南

基于sklearn的机器学习股票预测:特征工程与模型实战指南 简介机器学习在金融量化领域的应用日益普及其中使用sklearn进行股票预测是许多开发者入门时序建模的经典路径。理解其核心不在于直接预测未来价格而在于将非平稳的价格序列转化为有监督学习问题通过构造滞后特征、滚动统计量和技术指标来捕捉市场规律。特征工程的质量直接决定模型上限同时必须警惕数据泄漏——在时序任务中错误的交叉验证或特征缩放方式会让模型“偷看未来”导致评估结果虚高。借助随机森林、梯度提升树等集成模型配合TimeSeriesSplit和网格搜索进行严谨调优可以有效预测涨跌方向并评估泛化能力。该流程适用于量化分析、金融数据挖掘和算法交易策略研究等场景本文结合完整代码演示了从数据清洗、特征构造到模型评估的实操要点帮助开发者避开常见陷阱构建可靠的预测实验框架。1. 项目整体设计与思路拆解1.1 用sklearn做股票预测到底是在做什么先聊点实在的。股票预测这个方向很多初学者一听就觉得高大上以为能用机器学习算出明天涨还是跌甚至有人幻想做个模型就能躺着赚钱。作为一个在这条路上踩过不少坑的人我得先泼盆冷水股票预测的难点从来不在“跑通一个模型”而在于你是否想清楚了预测的目标是什么、数据怎么处理、怎么评估结果才不算自欺欺人。这个项目标题叫“基于sklearn模型的机器学习股票预测”核心其实就是把sklearn里那一堆经典模型——线性回归、随机森林、SVR、梯度提升树这些——用到股票行情数据上尝试从历史价格、成交量等特征中找出某种规律去预测未来的价格走势或涨跌方向。它能做的事情很明确帮你理解机器学习处理时序数据的基本流程验证不同模型在金融数据上的表现差异以及建立一个完整的预测实验框架。至于能不能靠它稳定赚钱那是另一回事后面我会详细说。适合来看这篇文章的人我觉得有三类一是正在学sklearn、想找个实际项目练手的学生二是想入门量化分析、但还没接触深度学习的开发者三是已经跑过一些模型但总觉得结果不对劲、想搞明白怎么评估和避坑的实践者。这篇文章不会教你用LSTM那种深度学习方案因为那是另一个量级的话题sklearn这套东西胜在简单、透明、易复现。1.2 为什么选择sklearn而不是深度学习或其他方案这个问题几乎是每个拿到这个项目的人都会问的。我的回答是先看你要解决什么问题。如果只是想快速搭建一套预测流程验证特征工程思路是否有效sklearn绝对是最合适的选择。它API统一、文档完善、模型种类多从线性模型到树模型到核方法全都覆盖生态里还有pipeline、网格搜索、特征选择这些配套工具几行代码就能搭出一个完整实验。深度学习当然也能做LSTM、Transformer在时间序列预测上确实有更强的序列建模能力但代价是什么数据量要求大、调参复杂度高、训练时间长、可解释性差。股票数据本身就充满噪声你用深度学习拟合出来的结果很多时候是过拟合而不是找到了真正的规律。另外还有几个很现实的原因让我在项目初期选择sklearn数据量不大时树模型和线性模型往往比神经网络更稳定。我测试过几千行日线数据用随机森林跑出来的效果并不比调了好几天的LSTM差多少甚至在某些指标上更好。sklearn的模型接口一致fit/predict一把梭对比不同算法非常方便。你不需要为每个模型学一套新的调用方式。做特征工程的时候sklearn的pipeline可以帮你把数据预处理和模型训练封装在一起减少出错概率。当然这个选择也不是没有局限。sklearn里没有一个真正意义上的时序模型它对时间依赖关系的学习能力有限所以后面做特征工程时我们需要手动构造滞后特征、滚动统计量这些来补偿。这个思路搞清楚了你就知道用sklearn做股票预测的本质是把时序问题转化成传统的监督学习问题。1.3 核心需求解析预测价格还是预测涨跌很多人拿到数据就开始跑回归模型预测明天的收盘价这是个典型的新手误区。我当初也是这样干的跑出来一看R²接近0.99当时的内心活动是这玩意儿能发财啊后来才意识到问题大了。为什么直接预测价格看着效果很好但实际没用因为价格序列本身是高度自相关的——今天的收盘价和明天的收盘价在数值上非常接近模型只要学会“复制昨天的价格”就能得到很低的误差。但这不是预测这是滞后。你在训练集上看到的那种好效果到了真实场景里完全失灵因为市场一旦出现跳空或者趋势反转这种模型毫无反应能力。所以我在这个项目里最终确定的目标是预测涨跌方向。具体来说有两种做法分类任务预测明天是涨还是跌用逻辑回归、随机森林、SVM这些分类器。回归任务再转换先预测明天的收益率然后根据收益率正负决定做多还是做空。我个人更推荐第二种。因为收益率序列比价格序列更平稳而且直接把价格数值作为预测目标时损失函数会过分关注大数值样本导致小波动的方向判断被忽略。而且预测收益率可以自然地转换成多分类或排序问题比如预测涨跌幅区间给交易决策提供更精细的信息。这个思路转变是这个项目最关键的一步。一旦你想明白了“预测目标不是价格而是方向”后面所有的数据处理、特征选择、模型评估才有意义。2. 数据准备与特征工程2.1 数据源选择与数据清洗做股票预测没有数据什么都是空谈。我一般用这三个数据源各有优劣大家可以根据实际情况选akshare免费、A股数据覆盖比较全接口简单适合个人研究。但它毕竟是免费接口数据偶尔会有缺失或复权不完整的情况使用前一定要做校验。yfinance老牌的免费美股数据接口数据质量相对稳定但国内网络访问不太稳定有时候需要重试。Tushare Pro需要注册获取token有积分门槛但数据质量高、字段丰富适合做严肃研究的场景。我这次用的是akshare拉取的某只股票的日线数据字段包括日期、开盘价、最高价、最低价、收盘价、成交量、成交额。拿到原始数据后第一件要做的事是清洗检查有没有NaN值发现缺了就前向填充或者删除。股票数据里偶尔会因为停牌产生空行直接删除比填充更干净。检查有没有重复日期特别是跨市场的数据拼接时容易出现。处理复权因子。这里要特别说一下如果用不复权的数据历史上发生除权除息的那一天会出现价格跳空模型会把它当作一个真实的波动来学习这就是噪声。我一般用前复权数据保证价格序列的连续性。清洗完的数据大概长这样每一行是一个交易日列是OHLCV各字段。至于要不要保留日期列我建议在构建特征之前先保留后面做特征衍生时要用到时间信息。2.2 特征工程从原始行情中构造有预测力的特征特征工程是sklearn股票预测项目里最值得花时间的环节。原始数据里的开高低收量这些字段直接扔给模型是能跑但效果一般因为模型看到的信息太原始了。我在这类项目中常用的特征可以分为几类第一类是滞后特征。也就是用过去几天的收盘价、收益率来构造特征。比如过去1天、3天、5天的收益率或者过去5日、10日的最高价和最低价。这类特征的逻辑是市场存在短期的动量或反转效应历史的价格变化会对未来有一定影响。第二类是滚动统计量。比如过去5日、10日、20日的移动平均线标准差以及最高价与最低价的差值。这些特征能帮助模型感知当前价格所处的相对位置和波动状态。另外布林带相关的特征也很有用价格与均线的距离、带宽百分比等。第三类是技术指标。像RSI、MACD、KDJ这些都是现成的技术指标可以自己算也可以用ta-lib库。但要注意技术指标不是加得越多越好。很多技术指标本质上是价格和均线的不同变换彼此之间高度相关加进去只会增加模型复杂度不会提升预测力。我一般只挑RSI和MACD的少数几个字段。第四类是日期类特征。比如星期几、月份、是否为月初。A股市场存在一定的星期效应和月初效应虽然信号不强但作为特征加进去成本很低可以试试。第五类是目标变量的滞后特征。这个要特别小心如果处理不当会造成数据泄漏。我的做法是构造完所有特征后统一用shift函数把目标变量往后移动一天确保模型在预测t时刻的目标时使用的所有特征都是在t-1时刻及之前就能获得的信息。关于特征数量我的经验是控制在20到30个左右就足够了。特征太多不仅训练慢还容易过拟合。sklearn里可以配合SelectKBest或者特征重要性排序来做筛选但我更建议先根据业务理解手工挑选再让模型自己排重要性不要一上来就交给机器自动选。2.3 数据泄漏问题千万不能忽视的坑数据泄漏这个坑我估计每一个做股票预测的人都踩过而且很多人踩了还不自知。举一个非常典型的例子。你想用过去10天的平均收益率预测明天的涨跌于是写代码的时候很自然地做了这么一件事计算过去10天的平均收益率然后用这个特征去训练模型。看起来没问题对吧问题出在你计算平均收益率的窗口里面如果包含了当天的数据而你的目标变量也是基于当天收盘价计算出来的那模型在训练时其实已经“看到”了一部分答案。还有一种更隐蔽的泄漏是在做特征缩放的时候。很多人习惯先对整个数据集做标准化再划分训练集和测试集。这在普通机器学习任务里问题不大但在时序数据里就是大忌。因为你用了全量数据的均值和标准差去缩放训练集就相当于训练集的数据已经偷看了测试集的分布信息。正确的做法是先划分训练集和测试集然后在训练集上fit标准化器再用这个已经fit好的标准化器去transform测试集。还有一个容易被忽略的是不要在特征构造阶段就用了未来数据。比如你想构造“过去5日最高价”如果窗口内包含了今天的数据而你的预测目标是明天的收益率这没有问题因为今天的数据在明天之前已经确定了。但如果你不小心把明天的数据也滑进窗口里那么就泄漏了。我的处理办法其实很简单就一句话特征值在时间t必须只使用[t-k, t]含t之前的信息目标变量必须是t1时刻的收益。每一列特征生成完之后我都会手动检查一遍有没有用到未来的行。3. 模型选型与训练策略3.1 sklearn中适合股票预测的模型横向对比sklearn里模型一大堆但不是每个都适合股票预测。我这次选了四个有代表性的来对比线性回归、随机森林、支持向量回归SVR和梯度提升树GradientBoostingRegressor。我分别说一下它们的特点和在这个场景下的表现。线性回归最简单假设特征和目标之间是线性关系。优点是解释性强训练速度快不容易过拟合到噪声上缺点也很明显金融数据里特征和目标的关系往往是非线性的所以它的预测能力上限不高。随机森林是bagging思想的代表通过多棵决策树投票来降低方差。它对异常值不敏感能处理非线性关系而且不容易过拟合是新手做股票预测的首选模型之一。我实测下来它在方向准确率上的表现通常比线性回归好不少。SVR利用核技巧把数据映射到高维空间再寻找最优超平面。它适合小样本、非线性的场景但缺点是参数敏感、训练速度慢而且对特征尺度非常敏感必须做标准化。在股票数据上我用它试过多次效果不太稳定不如树模型稳定。梯度提升树是boosting思想的代表每棵树都在拟合前面的残差。它的拟合能力很强往往是在这类任务里表现最好的模型之一。但正因为它拟合能力强如果不对树的深度和学习率做限制很容易过拟合。下面是我用同一份数据跑出来的对比结果的一个简化示意表模型训练集R²测试集R²方向准确率特点线性回归0.120.0852.3%简单快速但上限低随机森林0.350.1154.8%稳定可靠新手首选SVR0.280.0551.9%参数敏感不太稳定梯度提升树0.420.1356.1%拟合强需控制过拟合数据量不同、特征不同结果会不一样但整体趋势基本是树模型优于线性模型梯度提升树往往能冲到最高分但需要仔细调参。3.2 训练集与测试集划分方式普通机器学习任务里我们常常用train_test_split随机划分数据。但股票数据是时间序列随机划分会直接导致数据泄漏——同一只股票前后的样本之间有强烈的自相关性测试集里可能会包含和训练集时间上重叠或紧邻的数据模型等于间接“看到”了未来。正确的做法是按时间顺序切分。比如我有2000天的数据前1600天做训练中间200天做验证最后200天做测试。这样才能模拟真实的预测场景你永远是在用历史数据预测未来。如果你还想做更严谨一点的验证可以用时间序列交叉验证。sklearn里提供了TimeSeriesSplit类它和普通的KFold不一样每一折的训练集只会使用当前测试折之前的数据不会偷看未来。这样能得到更稳定的评估结果。我在这个项目里的策略是先用TimeSeriesSplit做初步调参确定超参数范围后再用固定的时间划分跑最终的测试集。这样做既利用了更多数据来调参又保证了最终评估的公正性。3.3 超参数调优用GridSearchCV还是手动调sklearn里的网格搜索GridSearchCV非常方便但我建议不要直接用它默认的参数范围去搜尤其是时间序列数据下交叉验证的方式本身就需要注意。一个容易踩的坑是GridSearchCV默认用的是普通的交叉验证即使你传入的X是按时间排序的它依然会随机划分这又会导致数据泄漏。正确的做法是在GridSearchCV里传入一个TimeSeriesSplit对象作为cv参数。比如from sklearn.model_selection import GridSearchCV, TimeSeriesSplit tscv TimeSeriesSplit(n_splits5) param_grid { n_estimators: [100, 200, 300], max_depth: [3, 5, 7], learning_rate: [0.01, 0.05, 0.1] } gbr GradientBoostingRegressor(random_state42) grid_search GridSearchCV(gbr, param_grid, cvtscv, scoringneg_mean_squared_error, n_jobs-1) grid_search.fit(X_train, y_train)注意这里scoring我用的负均方误差因为sklearn的评分函数默认是“越大越好”所以要用负号把误差转成得分。另外网格搜索的参数范围怎么定我一般先粗调一遍——用比较宽的步长快速走一遍确定最优参数大概在哪个区域然后再微调。不要把参数范围定得太细否则搜索时间会爆炸。比如learning_rate先用[0.01, 0.05, 0.1]粗调确定了在0.05附近后再用[0.03, 0.04, 0.05, 0.06]精调。还有一个经验之谈对树模型来说max_depth和n_estimators是一对冤家。树越深需要的树越少树越浅需要的树越多。所以调参的时候要一起看先固定一个粗略的learning_rate然后同时调这两个参数找到平衡点。4. 实操过程与核心环节实现4.1 环境准备与依赖安装动手之前先把环境准备好。我建议用Python 3.9以上的版本安装以下依赖pip install pandas numpy scikit-learn matplotlib akshare如果你还打算用ta-lib算技术指标安装会稍微麻烦一点Windows上需要先装对应的whl文件。我的建议是如果只是学习阶段不需要装ta-lib用pandas手动算RSI和MA就够了实现起来也不复杂。安装完成后先跑一个小脚本确认sklearn版本正常import sklearn print(sklearn.__version__)我用的是1.3以上的版本接口上有些细微差别但整体不影响。4.2 数据获取与预处理代码先用akshare拉取数据。这一步比较简单但要记得设置好日期范围和数据频率。import akshare as ak import pandas as pd import numpy as np # 拉取前复权日线数据 df ak.stock_zh_a_hist(symbol600519, perioddaily, start_date20150101, end_date20240101, adjustqfq) # 字段重命名 df.columns [date, open, close, high, low, volume, amount, amplitude, pct_change, change, turnover] df df[[date, open, close, high, low, volume]] df[date] pd.to_datetime(df[date]) df df.set_index(date).sort_index()这里我拉的是贵州茅台的日线数据做演示。你换成任何其他股票代码都可以注意不同市场的接口不一样akshare对应不同的函数名。拿到数据后先做基本清洗# 删除缺失行 df df.dropna() # 计算收益率目标是下一日的收益率 df[return_1d] df[close].pct_change() df[target] df[return_1d].shift(-1) # 删除最后一行因为最后一天没有未来数据 df df.dropna()这里shift(-1)是关键我们预测的是“明天的收益率”所以用当天的特征去学习后一天的收益。shift函数把收益率往上移了一行这样在时间t这一行target就是t1时刻的收益率。4.3 特征构造的完整实现接下来构造特征。我把前面提到的几类特征都用pandas向量化操作来实现避免写循环速度会快很多。# 滞后特征过去1、3、5天的收益率 for lag in [1, 3, 5]: df[freturn_lag_{lag}] df[return_1d].shift(lag) # 滚动统计量 for window in [5, 10, 20]: df[fma_{window}] df[close].rolling(window).mean() df[fstd_{window}] df[close].rolling(window).std() df[fmax_{window}] df[high].rolling(window).max() df[fmin_{window}] df[low].rolling(window).min() # 价格位置特征收盘价在近期高低点区间中的相对位置 df[close_position_5] (df[close] - df[min_5]) / (df[max_5] - df[min_5] 1e-10) df[close_position_10] (df[close] - df[min_10]) / (df[max_10] - df[min_10] 1e-10) # RSI指标14日 delta df[close].diff() gain delta.clip(lower0) loss -delta.clip(upper0) avg_gain gain.rolling(14).mean() avg_loss loss.rolling(14).mean() rs avg_gain / (avg_loss 1e-10) df[rsi_14] 100 - (100 / (1 rs)) # 成交量变化率 df[volume_ratio_5] df[volume] / df[volume].rolling(5).mean() # 日期特征 df[weekday] df.index.dayofweek df[month] df.index.month # 删除构造过程中产生的NaN行 df df.dropna()这里有几个细节值得说道说道。加1e-10是为了防止除以零因为股票可能连续几天最高最低价一样区间变成0除出来就是inf。还有滚动窗口计算时前20行会因为窗口不足而产生NaN最后统一dropna处理。4.4 模型训练与评估代码特征构造完成后把特征列和目标列分开然后按时间顺序切分数据集feature_cols [col for col in df.columns if col not in [target]] X df[feature_cols].values y df[target].values # 按时间顺序切分前70%训练后30%测试 split_idx int(len(df) * 0.7) X_train, X_test X[:split_idx], X[split_idx:] y_train, y_test y[:split_idx], y[split_idx:] print(f训练集样本数: {len(X_train)}, 测试集样本数: {len(X_test)})这里注意几个操作细节一是计算split_idx用的是int取整如果数据量不凑整后面的切片不会越界因为Python切片允许超出长度的索引二是我没有用train_test_split函数因为随机切分在这个场景是错误的必须手动按位置切。标准化处理from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)注意这里fit_transform只用了X_trainX_test只调用transform不能重新fit否则就泄漏了测试集信息。训练模型from sklearn.ensemble import GradientBoostingRegressor model GradientBoostingRegressor( n_estimators300, max_depth5, learning_rate0.05, subsample0.8, random_state42 ) model.fit(X_train_scaled, y_train) y_pred model.predict(X_test_scaled)评估指标我建议用两个维度来看一个是数值误差层面的均方根误差RMSE和R²另一个是业务层面的方向准确率。from sklearn.metrics import mean_squared_error, r2_score mse mean_squared_error(y_test, y_pred) rmse np.sqrt(mse) r2 r2_score(y_test, y_pred) # 方向准确率 direction_pred np.sign(y_pred) direction_true np.sign(y_test) direction_acc np.mean(direction_pred direction_true) print(fRMSE: {rmse:.6f}) print(fR²: {r2:.4f}) print(f方向准确率: {direction_acc:.2%})方向准确率可以简单地理解为模型每次给出的涨跌判断与实际涨跌一致的比例。这个指标比R²更贴近交易场景因为实际做决策时你更需要的是方向正确而不是数值精确。4.5 特征重要性分析与模型可解释性树模型有一个天然优势就是可以输出特征重要性。这个功能非常有用能帮你验证特征工程到底有没有效果以及找出哪些特征是真正有预测力的。import matplotlib.pyplot as plt feature_importance model.feature_importances_ indices np.argsort(feature_importance)[::-1] for i in range(min(15, len(feature_cols))): print(f{i1}. {feature_cols[indices[i]]}: {feature_importance[indices[i]]:.4f})我跑完后的特征重要性排序排在前面的通常是近期收益率、价格位置特征和RSI日期特征基本垫底。这说明市场短期动量信息对预测方向的贡献最大而星期几、月份这类日历效应在个股层面确实很弱。这个结果反过来可以帮助你简化特征集。那些重要性评分长期接近0的特征直接删掉就行留着只会增加噪声和过拟合风险。5. 常见问题与排查技巧实录5.1 训练集效果很好但测试集一塌糊涂这是最常见的困惑几乎每个人都经历过。训练集R²很高到了测试集直接变成负值方向准确率掉到50%上下跟抛硬币差不多。我分析下来原因主要有三个。第一个是数据泄漏比如特征里包含了未来信息或者标准化时偷看了测试集分布。第二个是过拟合模型把训练数据里的噪声也学进去了真实场景里这些噪声不复现预测自然失灵。第三个更根本——股票市场本身就有很强的随机性有效市场假说认为价格已经反映了所有公开信息也就是说可预测的信号本身就很微弱。怎么排查呢第一步先检查数据泄漏把每个特征的构造时间对齐关系过一遍确认shift的对齐是否正确。第二步看训练集和测试集的特征分布是否一致用describe对比几个关键特征的均值和标准差如果差异很大说明市场环境已经发生了变化模型失效是正常的。第三步是观察训练曲线如果训练集误差随着树的数量增加持续下降但验证集误差先降后升那就是过拟合需要限制树深度或增大正则化参数。我在实际项目里遇到的情况比较真实不管怎么调参方向准确率基本就在52%到56%之间徘徊。这说明模型确实学到了一些微弱信号但远达不到稳定盈利的程度。这就是金融预测的常态。5.2 时间序列交叉验证与GridSearchCV的配合网格搜索里的cv参数必须在时间序列场景下设置为TimeSeriesSplit这一点我再强调一遍都不为过。很多人用GridSearchCV默认的KFold结果交叉验证分数虚高模型上线后却打回原形。一个推荐的写法from sklearn.model_selection import TimeSeriesSplit, GridSearchCV tscv TimeSeriesSplit(n_splits5) param_grid { n_estimators: [100, 200], max_depth: [3, 5], learning_rate: [0.01, 0.05] } gbr GradientBoostingRegressor(random_state42) grid GridSearchCV(gbr, param_grid, cvtscv, scoringneg_mean_squared_error, n_jobs-1) grid.fit(X_train_scaled, y_train) print(f最佳参数: {grid.best_params_})这里TimeSeriesSplit(n_splits5)的含义是把数据按顺序分成6份第一次用前1份训练、第2份验证第二次用前2份训练、第3份验证以此类推。这样每一折都是“用过去预测未来”和你的实际使用场景一致。不过还有一点要提醒TimeSeriesSplit每折的训练集大小不一样越往后训练数据越多验证的样本量相对越小。如果你对某一段特定时间更关心可以只做固定窗口的划分用前N天训练、后M天验证然后手动滑动窗口来做多次验证。这个方式更能反映模型在不同市场环境下的稳定性。5.3 收益率预测值非常接近0怎么办跑完回归模型后你会发现预测的收益率集中在0附近方差很小。这不是bug这是模型的正常行为。原因是模型在训练时看到了大量的微小波动样本为了最小化整体误差它会倾向于输出一个安全的中间值——接近于均值的方向。换句话说模型发现“猜0”的惩罚最小就学成了一个偏保守的预测器。针对这个问题有几个改进方向。一是可以改成分类问题直接预测上涨、下跌、震荡三类让模型逼着自己在类别之间做选择而不是输出一个模棱两可的数字。二是换一个决策导向的损失函数比如在这个场景里预测方向错误带来的“代价”远大于预测数值偏差的代价你可以自定义评分函数传入GridSearchCV的scoring参数让调参过程直接优化方向准确率。三是增加更多高信噪比的特征好的特征能让模型更有信心地输出偏离0的预测值。5.4 常见问题速查表问题现象可能原因解决办法训练集R²接近0.99测试集很差数据泄漏特征包含未来信息检查shift对齐确认特征只使用t时刻及之前数据预测值全部接近0模型倾向于输出均值改为分类任务或自定义方向相关损失特征重要性全部接近0特征本身没有预测力或目标过于随机增加特征维度检查目标变量是否存在可预测性标准化时报错测试集包含未知类别或缺失值在训练集上fit测试集只做transform方向准确率长期在50%附近市场本身接近随机游走模型中未能学到强规律降低预期用更严格的评估标准考虑更长预测周期网格搜索跑得太慢参数组合太多训练样本太大先粗调缩小范围使用TimeSeriesSplit较少折数开启n_jobs并行5.5 不要为了追求高准确率而过度拟合这是我最想提醒初学者的一点。看到模型的方向准确率从55%调到57%时很容易产生一种“再调一调就能发财”的错觉然后开始不断加特征、调参数、反复测试直到在测试集上得到一个漂亮的数字。但这时候你多半已经过拟合到测试集上了。正确的做法是留一块你从没碰过的数据作为真正的最终验证集。在整个调参过程中完全不看它等所有决定都做完了最后跑一次得到结果这个结果才是相对可信的。如果模型在这个从未见过的数据上表现还行才算有一定的泛化能力。我在这个项目里专门留了最后半年数据没动调完所有参数后跑了一次方向准确率大约53.8%和验证集的表现差不多。坦白说这个结果说明模型确实学到了一些东西但距离“预测股票”这个目标还很远。这个项目真正有价值的部分是流程搭建、特征工程和评估方法的整套方法论这套东西后续接到其他数据源、其他模型上都一样适用。6. 进一步优化方向6.1 从回归到分类的转换实践如果你想进一步优化我建议把回归问题转为分类问题再试一次。目标变量从“明天的收益率”变成“明天是上涨还是下跌”用逻辑回归、随机森林分类器或梯度提升分类器来训练。分类的好处是模型不再被迫去拟合微小波动而是专注于学习区分类别的边界。这通常能带来更好的方向准确率。还有一种中间态的做法是预测三分类上涨、横盘、下跌把|收益率|小于某个阈值比如0.5%都归为横盘减少噪声标签对模型的扰动。6.2 集成策略与多模型融合单一模型始终有上限。你可以在完成基础模型后尝试用VotingRegressor或StackingRegressor把不同模型的预测结果组合起来。随机森林捕捉非线性但容易在样本边界处失真线性回归捕捉全局趋势但很粗糙SVR在某些局部区间表现好但整体不稳。把这三个模型的结果做加权平均往往比任何一个单模型都要稳。加权系数可以用验证集上的表现来定而不是拍脑袋。from sklearn.ensemble import VotingRegressor rf RandomForestRegressor(n_estimators200, max_depth5, random_state42) lr LinearRegression() svr SVR(kernelrbf, C1.0, epsilon0.01) voting VotingRegressor(estimators[ (rf, rf), (lr, lr), (svr, svr) ], weights[0.5, 0.2, 0.3]) voting.fit(X_train_scaled, y_train)权重的合理性在于随机森林在大样本上更稳给更高的权重线性回归和SVR作为辅助提供差异化的预测视角。最终的集成效果一般不会比最差模型差很多时候会好于任何一个单独模型。6.3 扩展到多股票与多周期如果你不满足于只预测一只股票的涨跌可以尝试把多只股票的数据拼在一起训练一个模型。这样做的逻辑是不同股票之间可能存在共同的因子和联动效应模型可以学到一些跨股票的通用规律。但要注意标准化方式每只股票的特征应该单独标准化否则不同股票的股价水平差异会干扰模型。多周期同步预测也是进阶方向。日线数据之外可以加入周线、月线的特征比如“过去4周趋势”“月线RSI”这类跨尺度信息提供与日线不同的视角。个人经验与最后的实操心得这个项目做完之后我最大的体会是用sklearn做股票预测这件事模型本身反而是最简单的部分难的是数据处理、特征工程、评估设计和对你预期的管理。我见过太多人跑出一个R²很高的模型后兴奋不已结果实盘一用就怀疑人生。真正的经验是把评估目标从“拟合精度”切换到“方向准确率”把期望值从“一本万利”调到“验证方法论”你会发现这个项目能带给你的价值远超预期。你会真正理解数据泄漏的严重性、特征工程的粒度对模型效果的影响、时序数据评估与普通机器学习评估的本质差异。这些技能换到任何机器学习任务上都是通用的。最后再分享一个小技巧每次跑完实验把模型参数、特征列表、评估指标都记录下来。时间一长你会积累出一张“什么特征在什么市场环境下有效”的经验表这个经验表比任何单个模型都值钱。本文还有配套的精品资源点击获取
返回列表