ARTICLE DETAIL

资讯详情

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

线性回归股票预测实战:从数据挖掘到滚动回测的完整指南

线性回归股票预测实战:从数据挖掘到滚动回测的完整指南 简介这份资源面向具备Python基础、希望入门数据挖掘与机器学习实战的学习者聚焦线性回归在股票预测中的完整落地流程。内容围绕数据获取与清洗、特征工程、模型训练与预测评估展开涉及pandas数据处理、NumPy特征计算以及移动平均、MACD、RSI等技术指标的构建思路并借助sklearn的线性回归完成拟合通过MSE、RMSE与R²等指标衡量预测效果同时讨论了线性模型在非线性市场中的局限与改进方向。压缩包共2个文件包含1个py源码与1个pdf讲解文档整体约2.34MB源码可直接运行对照文档便于梳理原理与流程。目前已有4741人学习下载适合作为课程设计、项目练手或金融预测入门的参考案例帮助读者打通从数据预处理到模型评估的完整链路。1. 从一份股票预测源码说起线性回归到底能挖出什么很多人第一次接触数据挖掘和机器学习都是从一份股票预测的源码包开始的。打开一看无非是几个 CSV 文件、一个 Python 脚本跑完输出一条拟合直线和几个误差指标。但真正动手跑过的人会发现一个反直觉的现象同样的代码、同样的数据每次运行出来的预测结果居然不一样。这不是代码写错了而是机器学习流程里数据划分、随机种子、特征顺序这些环节在起作用。这份以线性回归为核心的股票预测案例本质上是一个完整的监督学习闭环数据获取、特征工程、模型训练、预测评估。它适合刚学完 Python 语法、想找一个能跑通的项目来理解机器学习全流程的人也适合已经会调库、但没认真想过每一步为什么这么做的开发者。线性回归虽然简单但它是理解更复杂模型的基石股票预测虽然噪声大但它是练习时间序列特征构造的绝佳场景。2. 数据挖掘与机器学习在股票预测里的分工先搞清楚谁干什么2.1 数据挖掘负责找关系机器学习负责学映射很多人把数据挖掘和机器学习混着说但在一个股票预测项目里两者的分工其实很清晰。数据挖掘阶段要做的是从原始行情数据里构造出有意义的特征比如把收盘价转成收益率、计算移动平均线、提取成交量变化率。这些操作不涉及模型纯粹是对数据的加工和探索。机器学习阶段则是拿这些特征去拟合一个目标变量比如明天的收盘价或者涨跌方向。线性回归在这里的角色是建立一个可解释的线性映射y w1x1 w2x2 ... b。权重 wi 表示每个特征对预测目标的影响方向和大小截距 b 是基准值。这个公式看起来简单但背后有几个关键假设特征与目标之间存在线性关系、误差项独立同分布、特征之间不能有严重共线性。股票数据往往不满足这些假设所以线性回归在股票预测里的定位不是追求最高精度而是作为一个可解释的基线模型。你先用它跑通流程知道哪些特征有正向贡献、哪些有负向贡献再考虑换更复杂的模型。2.2 从原始行情到特征矩阵一个可复现的构造流程假设你手里有一份包含日期、开盘价、最高价、最低价、收盘价、成交量的 CSV 文件。第一步是加载数据并检查缺失值。常见做法是用 pandas 读取然后按日期排序确保时间顺序正确。第二步是构造特征。对于股票预测最基础的特征包括前一日收盘价、前五日收盘价均值、前一日成交量、前一日涨跌幅。目标变量可以设为当日收盘价或次日收盘价。这里有一个容易翻车的地方如果你用当日收盘价去预测当日收盘价那就是数据泄露模型会给出完美结果但毫无意义。正确的做法是用 t 时刻及之前的数据预测 t1 时刻的值。第三步是划分训练集和测试集。时间序列不能随机打乱必须按时间顺序切分比如前 80% 作为训练集后 20% 作为测试集。下面是一个可复现的特征构造代码片段import pandas as pd import numpy as np # 读取数据假设文件名为 stock.csv df pd.read_csv(stock.csv, parse_dates[date]) df df.sort_values(date).reset_index(dropTrue) # 构造特征 df[ret_1] df[close].pct_change(1) # 前一日涨跌幅 df[ma_5] df[close].rolling(5).mean() # 前五日收盘价均值 df[vol_ratio] df[volume] / df[volume].rolling(5).mean() # 成交量比值 df[target] df[close].shift(-1) # 次日收盘价作为目标 # 去掉缺失值 df df.dropna().reset_index(dropTrue) # 按时间顺序划分 split int(len(df) * 0.8) train df.iloc[:split] test df.iloc[split:] feature_cols [ret_1, ma_5, vol_ratio] X_train train[feature_cols].values y_train train[target].values X_test test[feature_cols].values y_test test[target].values这段代码里pct_change(1)计算的是相邻两日的收益率rolling(5).mean()是滚动窗口均值shift(-1)把下一行数据上移一行作为目标。参数方面窗口大小 5 是一个经验值你可以改成 10 或 20但要注意窗口越大丢失的早期数据越多。dropna()会删掉因为滚动和移位产生的空值行这是必须的否则模型训练会报错。划分比例 0.8 是常见选择时间序列里不建议用随机划分因为那会引入未来信息。2.3 线性回归模型的训练与评估三个必调参数和两个评估指标训练线性回归模型在 scikit-learn 里只需要三行代码但要让结果稳定可复现有几个参数必须注意。第一个是fit_intercept默认是 True表示模型会计算截距项。如果你的特征已经做过标准化保留截距通常没问题但如果你的数据已经中心化到零均值可以设为 False 来减少一个参数。第二个是normalize这个参数在新版本里已经废弃正确的做法是在训练前用StandardScaler对特征做标准化。第三个是random_state线性回归本身没有随机性但如果你用了train_test_split或者后续要做交叉验证必须固定这个种子否则每次划分不同结果自然不一样。评估指标方面回归任务常用均方误差 MSE 和决定系数 R²。MSE 衡量预测值与真实值的平均平方偏差单位是目标变量的平方不好直接解释R² 表示模型解释了目标变量多少比例的方差越接近 1 越好但股票数据上通常只有 0.01 到 0.1 之间甚至为负。下面是一个完整的训练和评估代码from sklearn.linear_model import LinearRegression from sklearn.preprocessing import StandardScaler from sklearn.metrics import mean_squared_error, r2_score # 标准化特征 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) # 训练模型 model LinearRegression(fit_interceptTrue) model.fit(X_train_scaled, y_train) # 预测 y_pred model.predict(X_test_scaled) # 评估 mse mean_squared_error(y_test, y_pred) r2 r2_score(y_test, y_pred) print(fMSE: {mse:.4f}, R2: {r2:.4f}) print(系数:, model.coef_) print(截距:, model.intercept_)这里StandardScaler做了两件事减去均值、除以标准差。注意训练集用fit_transform测试集只能用transform否则测试集的统计量会泄露到训练过程中。model.coef_输出每个特征的权重正数表示该特征增加时预测值增加负数相反。如果某个特征的权重绝对值特别大说明它对预测影响很大但也可能是共线性导致的数值不稳定。R² 为负说明模型还不如直接拿均值去预测这在股票数据里很常见不必惊慌重点是理解流程。3. 把源码跑起来环境配置、数据替换和结果解读的完整路径3.1 Python 环境与依赖安装避开版本冲突的坑拿到一份源码包第一步不是急着运行而是先看它依赖哪些库。常见的组合是 pandas、numpy、scikit-learn、matplotlib。如果你用的是 Anaconda很多库已经预装了但版本可能和源码要求的不一致。我一般会创建一个独立的虚拟环境避免污染全局环境。命令如下python -m venv stock_env source stock_env/bin/activate # Linux/Mac # stock_env\Scripts\activate # Windows pip install pandas numpy scikit-learn matplotlib如果你在 Windows 上激活命令是stock_env\Scripts\activate。安装完成后用pip list检查版本。pandas 建议 1.3 以上scikit-learn 建议 1.0 以上。如果源码里用了normalize参数而你的 scikit-learn 是 1.2 以上会报错因为该参数已被移除。解决办法是把LinearRegression(normalizeTrue)改成先用StandardScaler标准化再训练LinearRegression()。另一个常见问题是 matplotlib 中文显示乱码需要在代码里加两行配置import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] FalseSimHei是黑体Windows 上一般都有Linux 上可能需要换成WenQuanYi Micro Hei或其他已安装的中文字体。axes.unicode_minus设为 False 是为了正常显示负号。3.2 替换自己的数据CSV 列名映射和日期格式处理源码包里的数据通常是示例数据你想用自己的股票数据跑一遍就需要做列名映射。假设你的 CSV 里列名是中文的“日期、开盘、最高、最低、收盘、成交量”而代码里用的是英文date, open, high, low, close, volume。有两种改法一是改代码里的列名二是读入后重命名列。我一般用后者不动源码逻辑df pd.read_csv(my_stock.csv) df df.rename(columns{ 日期: date, 开盘: open, 最高: high, 最低: low, 收盘: close, 成交量: volume }) df[date] pd.to_datetime(df[date]) df df.sort_values(date).reset_index(dropTrue)pd.to_datetime会把字符串转成时间戳如果日期格式不标准可以加format参数比如format%Y/%m/%d。排序和重置索引是必须的因为后面的滚动计算依赖顺序。如果你的数据里有停牌日或者缺失交易日pct_change会算出异常值建议先检查缺失情况必要时用前值填充或直接删除。3.3 预测结果怎么看残差图、系数表和滚动预测模型跑完输出 MSE 和 R² 只是第一步真正要看的是残差分布和系数含义。残差是真实值减去预测值如果残差围绕零随机分布说明模型没有系统性偏差如果残差呈现明显的趋势或周期性说明还有信息没被提取。画残差图的代码如下import matplotlib.pyplot as plt residuals y_test - y_pred plt.figure(figsize(10, 4)) plt.subplot(1, 2, 1) plt.plot(residuals) plt.title(残差序列) plt.subplot(1, 2, 2) plt.hist(residuals, bins30) plt.title(残差分布) plt.show()系数表可以帮你理解每个特征的影响。比如ret_1的系数是正的说明前一日涨跌幅对次日收盘价有正向影响vol_ratio的系数是负的说明成交量放大时次日价格可能下跌。但要注意这些系数是在标准化之后得到的比较的是相对重要性不是原始单位下的变化量。滚动预测是更贴近实盘的验证方式每次用过去一段窗口训练预测下一天然后窗口向前滑动。这样能看出模型在不同时间段的表现是否稳定。如果某段时间 R² 突然变负说明市场结构可能发生了变化模型需要重新训练。4. 避坑与排查股票预测里那些让你白忙一天的细节4.1 现象每次运行结果都不一样R² 忽高忽低原因通常有三个一是没有固定随机种子如果你用了train_test_split或者任何带随机性的步骤必须设random_state二是数据划分方式不对时间序列如果随机打乱每次划分不同结果自然不同三是特征标准化时用了全部数据导致测试集信息泄露。解决方法是固定random_state42按时间顺序切分标准化只在训练集上fit。4.2 现象模型在训练集上 R² 很高测试集上为负这是典型的过拟合。线性回归本身不容易过拟合但如果特征数量接近甚至超过样本数量或者特征之间存在严重共线性就会出现这种情况。解决方法是减少特征数量、使用正则化Ridge 或 Lasso、或者增加样本量。股票数据里如果你用了太多技术指标很容易陷入过拟合。我一般会先只保留三到五个核心特征跑通后再逐步增加。4.3 现象预测值是一条直线完全不波动原因可能是目标变量选错了。如果你用当日收盘价预测当日收盘价或者特征里包含了目标变量的直接衍生项模型会直接学到恒等映射。另一个可能是特征没有标准化导致某些大数值特征主导了权重。解决方法是检查特征和目标的时间对齐关系确保用 t 时刻预测 t1 时刻并对特征做标准化。4.4 现象CSV 读取报错提示列不存在或类型错误常见原因是列名有空格、编码不对、或者日期列被当成了字符串。解决方法是先用df.columns打印列名确认没有多余空格用df.info()查看每列类型如果编码是 GBK读取时加encodinggbk。日期列用pd.to_datetime转换转换失败的行可以用errorscoerce变成 NaT然后删掉。4.5 现象画图时中文显示成方框这是 matplotlib 字体配置问题。Windows 上设置plt.rcParams[font.sans-serif] [SimHei]Mac 上可以用[Arial Unicode MS]Linux 上需要先确认系统安装了中文字体然后用fc-list :langzh查看可用字体名称再配置到font.sans-serif里。改完配置后需要重启 Python 内核才能生效。5. 从线性回归到滚动回测一个更接近实盘的验证习惯线性回归跑通之后很多人会直接看测试集上的 R² 就下结论。但股票预测里单次划分的测试结果偶然性很大。我后来养成了一个习惯做滚动回测。具体做法是设定一个训练窗口比如 250 个交易日然后每次用窗口内的数据训练预测窗口后一天窗口向前滑动一天重复这个过程。这样能得到一条完整的预测序列再计算整体的 MSE 和 R²。代码实现如下def rolling_backtest(df, feature_cols, window250): preds [] trues [] for i in range(window, len(df) - 1): train df.iloc[i-window:i] test df.iloc[i:i1] X_train train[feature_cols].values y_train train[target].values X_test test[feature_cols].values y_test test[target].values scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) model LinearRegression() model.fit(X_train_scaled, y_train) pred model.predict(X_test_scaled) preds.append(pred[0]) trues.append(y_test[0]) mse mean_squared_error(trues, preds) r2 r2_score(trues, preds) return mse, r2, preds, trues这个函数里window250大约是一年的交易日数量你可以根据数据长度调整。每次循环都重新fit标准化器确保只用历史信息。跑完滚动回测后把预测值和真实值画在一起能直观看到模型在哪些时间段表现好、哪些时间段失效。如果整体 R² 仍然很低不要灰心股票预测本身就是高噪声任务线性回归的价值在于提供一个可解释的基线。你可以在这个基础上尝试加入更多特征、换用 Ridge 回归做正则化、或者把目标变量从收盘价改成涨跌方向做分类。但无论怎么改滚动回测这个验证习惯都值得保留它比单次划分更能反映模型的真实泛化能力。希望帮到你。本文还有配套的精品资源点击获取
返回列表