Python机器学习实战:基于sklearn的股票预测代码骨架与数据准备 简介这是一套面向高校学生与机器学习入门者的股票预测实战项目基于Python与sklearn构建适合用作毕业设计、期末大作业或课程设计的高分参考方案。资源包共14个文件包含4个py源码脚本、6个xml配置文件、1个csv数据集、1个txt依赖说明及gitignore、iml等工程文件压缩包约24.25MB结构清晰部署简单。代码围绕随机森林等sklearn模型展开从数据获取、特征处理到模型训练与预测均有完整实现并配有详细注释新手也能逐步理解。数据文件与依赖清单齐备下载后可直接运行调试省去自行搜集数据与配置环境的时间。目前已有245人学习下载作者为qq_38140936。对于需要快速搭建股票预测demo、撰写论文实验章节或完成课程作业的读者这份资源能提供可复用的代码框架与排错思路帮助在有限时间内产出规范、可展示的成果。1. 用 sklearn 做股票预测一份能跑通的代码骨架长什么样很多人第一次搜「python机器学习基于sklearn模型的股票预测代码所需数据」心里想的其实是有没有一份能直接跑、数据也配齐的代码让我先看到结果再回头理解原理。这个诉求很实在因为股票预测这个场景光看算法推导容易飘只有把数据喂进去、模型跑起来、指标打出来才知道坑在哪。我一般会先搭一个最小可复现的骨架用公开行情数据构造几个常见特征跑通线性回归、随机森林、梯度提升三类 sklearn 模型最后用均方误差和方向准确率两个指标对比。这套骨架不追求实盘盈利它的价值在于让你把「数据获取→特征工程→时序切分→训练→评估」整条链路走一遍后面换数据、换特征、换模型都有地方下手。适合刚学完 sklearn 基础、想找一个完整项目练手的人也适合做量化策略但想补机器学习环节的开发者。2. 数据与特征股票预测的输入到底怎么准备2.1 行情数据从哪来、要哪些字段股票预测代码能不能跑第一道坎不是模型是数据。常见做法是用公开的日线行情字段至少包含日期、开盘价、最高价、最低价、收盘价、成交量。如果你手头没有现成 CSV可以用 pandas 从本地行情文件读或者用 akshare、tushare 这类库拉取。注意这里不涉及任何交易接口的实盘对接只是拿历史数据做离线训练。我一般会把数据整理成一张宽表索引是交易日列是各字段。读进来之后先做三件事按日期升序排列、检查缺失值、把日期列转成 datetime 类型。顺序错了后面所有滚动特征都会错位这是血泪经验。import pandas as pd import numpy as np # 读取本地行情 CSV假设列名为 date, open, high, low, close, volume df pd.read_csv(stock_daily.csv, parse_dates[date]) df df.sort_values(date).reset_index(dropTrue) # 缺失值处理行情数据一般用前向填充避免直接删行导致时间不连续 df[[open, high, low, close, volume]] ( df[[open, high, low, close, volume]].ffill() ) # 去掉仍然缺失的行通常是数据开头 df df.dropna().reset_index(dropTrue) print(df.head()) print(df.shape)这段代码的逻辑很直白先保证时间有序再处理缺失。参数上parse_dates把日期列解析成时间类型ffill是前向填充适合行情这种连续交易日场景。如果你用的是分钟级数据缺失处理要更谨慎因为停牌和休市含义不同。2.2 特征工程把价格变成模型能吃的数字原始价格不能直接喂给模型因为绝对价格没有可比性而且不同股票价格量级差异大。常见做法是构造收益率、滚动均值、滚动波动率、成交量变化率这几类特征。收益率用pct_change()滚动均值用rolling(window).mean()波动率用滚动标准差。窗口参数我一般从 5、10、20 三个里选对应一周、两周、一个月。# 日收益率 df[ret_1] df[close].pct_change() # 滚动均值与波动率 for w in [5, 10, 20]: df[fma_{w}] df[close].rolling(w).mean() df[fvol_{w}] df[ret_1].rolling(w).std() # 成交量变化率 df[vol_chg] df[volume].pct_change() # 预测目标下一日收益率方向涨为 1跌为 0 df[target] (df[close].shift(-1) df[close]).astype(int) # 去掉滚动窗口和 shift 产生的空值 df df.dropna().reset_index(dropTrue)这里有几个参数要留意。rolling(w)的窗口越大特征越平滑但滞后越明显shift(-1)是把明天作为预测目标训练时不能把今天之后的信息混进来。目标列用方向而不是具体价格是因为价格回归在股票上极难做准方向分类至少能看出模型有没有学到东西。提示特征构造完一定要检查有没有未来函数。比如用close算的滚动均值如果窗口包含了当天收盘而预测目标又是下一日那当天收盘是已知的没问题但如果用shift(-1)后的价格去算特征就泄露了。3. 用 sklearn 跑通三类模型从线性回归到集成树3.1 时序切分为什么不能随机打乱股票数据是典型的时间序列随机切分会让模型在训练集里看到未来数据评估结果虚高。正确做法是按时间顺序切前 80% 做训练后 20% 做测试。如果你要做交叉验证也得用TimeSeriesSplit不能用默认的 KFold。from sklearn.model_selection import TimeSeriesSplit feature_cols [c for c in df.columns if c not in [date, target]] X df[feature_cols].values y df[target].values # 按时间顺序切分 split_idx int(len(df) * 0.8) X_train, X_test X[:split_idx], X[split_idx:] y_train, y_test y[:split_idx], y[split_idx:] # 时序交叉验证 tscv TimeSeriesSplit(n_splits5) print(训练集样本数:, X_train.shape, 测试集样本数:, X_test.shape)TimeSeriesSplit的n_splits决定切几折每折训练集只包含测试集之前的数据。这个参数在样本量少的时候可以调小比如 3 折否则每折训练数据太短模型学不到东西。3.2 三个基线模型线性回归、随机森林、梯度提升sklearn 的好处是接口统一换模型基本只改一行。我一般先跑逻辑回归做线性基线再跑随机森林和梯度提升看非线性模型有没有提升。注意这里说的是分类任务所以用LogisticRegression而不是LinearRegression。如果你要做价格回归把目标换成下一日收益率模型换成Ridge或RandomForestRegressor。from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline from sklearn.metrics import accuracy_score, f1_score models { 逻辑回归: Pipeline([ (scaler, StandardScaler()), (clf, LogisticRegression(max_iter1000)) ]), 随机森林: RandomForestClassifier( n_estimators200, max_depth5, random_state42 ), 梯度提升: GradientBoostingClassifier( n_estimators200, max_depth3, learning_rate0.05, random_state42 ), } for name, model in models.items(): model.fit(X_train, y_train) pred model.predict(X_test) print(f{name} 准确率: {accuracy_score(y_test, pred):.4f} fF1: {f1_score(y_test, pred):.4f})参数上LogisticRegression的max_iter调大是为了防止不收敛随机森林的n_estimators是树的数量200 棵在几千条样本上够用max_depth限制深度防止过拟合梯度提升的learning_rate和n_estimators要配合调学习率小就多跑几轮。标准化只对逻辑回归必要树模型对量纲不敏感但放进 Pipeline 里统一处理更省事。3.3 评估指标准确率会骗人要看方向准确率和混淆矩阵股票涨跌方向如果分布不均准确率就没意义。比如 70% 的样本是涨模型全猜涨也有 70% 准确率。所以要看 F1、混淆矩阵以及单独算涨跌两个方向的表现。from sklearn.metrics import confusion_matrix, classification_report best_model models[梯度提升] pred best_model.predict(X_test) print(confusion_matrix(y_test, pred)) print(classification_report(y_test, pred, digits4))classification_report会给出每个类别的精确率、召回率和 F1。如果跌的召回率很低说明模型只会猜涨这种模型实盘没法用。我一般要求两个方向的 F1 都不能太差否则宁可不用。4. 避坑与排查股票预测代码最容易翻车的五个地方4.1 未来函数回测很美实盘就废现象训练集和测试集指标都很高换一段新数据就崩。原因特征里混入了未来信息比如用当天收盘算的指标去预测当天方向或者用shift(-1)后的数据做滚动统计。解决所有特征只能用当前及之前的数据目标列才用未来。检查方法是把特征列逐个和日期对齐看有没有用到shift(-n)且 n 为负的情况。4.2 数据对齐错误日期错位一天结果全变现象模型表现忽好忽坏换数据源就复现不了。原因不同数据源的日期格式、时区、停牌处理不一致合并时错位。解决统一用交易日索引合并前先sort_values和reset_index关键步骤打印前后几行核对。我习惯在特征构造后随机抽几天手工算一遍滚动均值和代码结果对一下。4.3 类别不平衡模型只会猜多数类现象准确率看着不错但混淆矩阵里一个类别几乎没预测对。原因涨跌样本比例悬殊模型偏向多数类。解决用class_weightbalanced或者对少数类过采样。注意过采样只能在训练集做测试集保持原始分布。4.4 过拟合训练集 F1 0.9测试集 0.5现象训练指标远高于测试指标。原因树太深、特征太多、样本太少。解决限制max_depth减少n_estimators加正则化或者用TimeSeriesSplit做交叉验证看稳定性。我一般先跑一个很浅的模型做基线再逐步加复杂度每加一步都看测试指标有没有提升。4.5 特征量纲与缺失值标准化和填充顺序搞反现象逻辑回归不收敛或者预测结果全是同一类。原因先标准化再填充缺失值导致填充值被缩放或者树模型遇到 NaN 直接报错。解决先填充再标准化Pipeline 里把填充和缩放按顺序排好。sklearn 的SimpleImputer可以放进 Pipeline但要注意strategy选median还是ffill取决于数据。5. 把代码变成可复用的实验参数调优与滚动验证5.1 用 GridSearchCV 配合 TimeSeriesSplit 调参单次切分评估波动大调参要用时序交叉验证。GridSearchCV可以传cvTimeSeriesSplit(n_splits5)这样每组参数都在时间序列上验证。from sklearn.model_selection import GridSearchCV param_grid { n_estimators: [100, 200, 300], max_depth: [3, 5, 7], learning_rate: [0.01, 0.05, 0.1], } gs GridSearchCV( GradientBoostingClassifier(random_state42), param_grid, cvTimeSeriesSplit(n_splits5), scoringf1, n_jobs-1, ) gs.fit(X_train, y_train) print(最佳参数:, gs.best_params_) print(最佳分数:, gs.best_score_)scoringf1比准确率更适合不平衡分类。n_jobs-1用满 CPU但数据量大时注意内存。调参范围不要一次铺太开先粗后细否则跑一晚上出不来结果。5.2 滚动训练模拟真实交易中的模型更新实盘里模型不能一次训练用到底要定期用新数据重新训练。滚动训练就是每过一段时间把窗口往前滑重新拟合。下面是一个简化版每 60 个交易日重新训练一次预测接下来 20 天。def walk_forward(X, y, train_window500, step60): results [] for start in range(0, len(X) - train_window - step, step): train_end start train_window test_end train_end step X_tr, y_tr X[start:train_end], y[start:train_end] X_te, y_te X[train_end:test_end], y[train_end:test_end] model GradientBoostingClassifier( n_estimators200, max_depth3, learning_rate0.05, random_state42 ) model.fit(X_tr, y_tr) pred model.predict(X_te) results.append(accuracy_score(y_te, pred)) return np.mean(results), np.std(results) mean_acc, std_acc walk_forward(X, y) print(f滚动验证准确率均值: {mean_acc:.4f} 标准差: {std_acc:.4f})train_window是每次训练用的历史长度step是往前滑的步长。窗口太短模型学不稳太长又跟不上市场变化。我一般从 500 个交易日开始试步长取 20 到 60。标准差比均值更重要标准差大说明模型在不同时间段表现不稳定实盘风险高。5.3 特征重要性看看模型到底在依赖什么树模型可以输出特征重要性这一步能帮你发现数据泄露和无效特征。model GradientBoostingClassifier( n_estimators200, max_depth3, learning_rate0.05, random_state42 ) model.fit(X_train, y_train) importances pd.Series(model.feature_importances_, indexfeature_cols) print(importances.sort_values(ascendingFalse).head(10))如果某个特征重要性异常高先怀疑它是不是包含了未来信息。比如vol_chg如果用了当天收盘后的成交量而预测目标是当天方向那就是泄露。正常情况收益率和滚动波动率应该排在前列但不会一家独大。5.4 一个具体技巧用概率输出做阈值调整分类模型默认阈值 0.5但股票预测里你可以调阈值来平衡精确率和召回率。比如只在高概率时交易减少交易次数但提高胜率。proba model.predict_proba(X_test)[:, 1] for thresh in [0.5, 0.55, 0.6, 0.65]: pred (proba thresh).astype(int) print(f阈值 {thresh} 准确率: {accuracy_score(y_test, pred):.4f} fF1: {f1_score(y_test, pred):.4f})阈值调高预测为涨的样本变少精确率可能上升但召回率下降。具体取多少要看你的策略能承受多少假信号。我一般会画一条阈值和 F1 的曲线选 F1 最高附近的阈值而不是死守 0.5。这套代码骨架我前后改过很多版最大的教训是别一上来就堆模型先把数据对齐和特征构造做扎实再跑基线最后才调参。股票预测没有后悔药未来函数一旦混进去回测再漂亮也是自欺欺人。希望帮到你。本文还有配套的精品资源点击获取