[机器学习研究七]训练/测试划分比例对模拟实盘的影响:100 只股票、4 年真实数据的可追溯实验

无名的人无名的人··6 浏览

摘要

本文研究一个机器学习选股中的基础问题:训练期与测试期的划分比例,如何影响模型在"模拟实盘段"(完全未见过未来数据)中的表现。实验使用 PandaAI 云数据接口的真实 A 股日线(沪深300 成分股 100 只,2020-01-01 至 2023-12-31,95,108 行面板),将最后 6 个月(2023-07~12)作为完全隔离的模拟实盘段,训练/测试比分别取 5:5、7:3、8:2 三组,单次训练不重训,以逻辑回归输出未来 5 日收益方向的概率。优化版(v2,7 个量价特征)结果显示:训练占比越高,模拟实盘表现越好且单调——实盘段 AUC 0.4405 → 0.4668 → 0.4888,实盘多空收益 -0.68% → -0.49% → -0.11%;但三组均未获得正 alpha,说明在纯量价动量特征下,划分比例只能"减轻损失",不能"创造收益"。对照实验(v1,30 只/18 个月/4 特征)给出相反方向的表面结果(实盘多空 +1.0% 左右),揭示出比划分比例重要得多的一阶变量:股票池、样本区间与特征集的选择,能整体翻转结论。

本文的第二个贡献是研究过程本身:本实验最初由 AI 研究助手执行,其产出的两张"结论表"经审计均为伪造——第一次没有任何运行产物,第二次的脚本用 np.random.seed(42) 生成假市值、假 PB、假换手特征冒充真实数据。本文完整记录了从伪造结论、运行超时、容器内存崩溃、到真实数据链路打通的每一步,所有失败数据与运行凭证均存档。核心方法论结论:划分比例是策略设计的二阶变量,而"锁定独立实盘段 + 审计每一个数字的来源"是一阶纪律。


一、引言

1.1 研究背景

"训练集/测试集 7:3 划分"是机器学习选股最常见的一条经验法则,但它的适用前提很少被检验:分类任务里 7:3 保证测试集有足够样本量;时间序列任务里测试集还必须与训练集在时间上不重叠;而在量化策略中,测试集之后还存在第三个更严苛的观察期——模拟实盘段(部署后不再调参、不再重训的真实运行状态)。本文把这三段明确分开,回答"划分比例到底影响哪一段、影响多大"。

1.2 问题提出

  • 训练占比提高(5:5 → 7:3 → 8:2)会让模拟实盘表现更好吗?
  • 测试段的读数能否代表实盘段?如果不能,是划分比例的问题还是窗口的问题?
  • 划分比例与股票池、特征集、样本区间相比,重要性排第几?

1.3 与系列前作的关系

[研究二] 在平台内做过滚动训练 GLM(每 21 日重训),[研究六] 研究了输出频率对净超额的影响。本文是系列首个单次训练、不做任何重训的实验——刻意保留"模型上线后不再更新"的最严苛设定,以隔离出划分比例本身的效应。


二、研究目的与实验设计

2.1 核心目标

  1. 在同一实盘段、同一特征集下,量化 5:5/7:3/8:2 三种划分对实盘表现的影响;
  2. 检验测试段读数与实盘段读数的偏离程度;
  3. 通过 v1/v2 两轮实验(不同池子/区间/特征)判断划分比例在整体研究中的重要性排序;
  4. 全程记录研究过程,包括失败与造假,形成可复核的实验档案。

2.2 实验设计(单变量原则之外的关键约束)

设计项 设定 说明
模拟实盘段 2023-07-01 ~ 2023-12-31(6 个月) 完全隔离,不参与任何训练/测试/调参
划分方式 训练窗与测试窗在实盘段之前的 3.5 年内按日期切分 5:5 / 7:3 / 8:2 三组
训练策略 单次训练,实盘段内不重训、不调参 最严苛的部署模拟
模型 逻辑回归(max_iter=100) 轻量、可复现,避免容量差异干扰
标签 未来 5 日收益的逐日截面分位(>0.5 为正类) 截面可比,去市场beta
特征预处理 逐日截面 rank 归一化到 [0,1] 去量纲、去极端值
评价 三段 AUC + 多空(预测前 20% vs 后 20%)收益率 AUC 看排序能力,多空看经济收益

三、数据与特征

3.1 数据来源

PandaAI 云数据接口 panda_data(EVO 云工作站内预装并完成鉴权),沪深300 成分股每 3 只取 1(100 只),2020-01-01 至 2023-12-31 日线。落盘 100 个逐票 CSV 缓存,合并后面板 95,108 行,有效样本(特征滚动窗与标签齐备)约 90,500 行。

3.2 特征集(v2,7 个)

特征 计算 经济含义
m5 / m20 / m60 5/20/60 日收益率 短期/中期/长期动量或反转
v20 20 日收益率标准差 波动率
t20 换手率 20 日均值 流动性与交易拥挤度
ar 成交额 / 20 日均额 - 1 异常放量
hl20 20 日平均 (最高-最低)/收盘 振幅/日内博弈强度

全部特征逐日做截面 rank 归一化;标签为未来 5 日收益的逐日截面分位,二分类标签取分位 > 0.5。


四、研究过程(可追溯)

本节按时间顺序记录全部步骤。红色为失败/伪造,橙色为工程故障,绿色为真实成功(见图 3 时间线)。

4.1 Step 1:首次尝试与三次超时(09:52-11:12)

任务最早交给 AI 研究助手执行(EVO 内测环境)。它先后提交了三个版本的数据准备脚本,每次都声称"正在拉取 2010-2023 全市场面板",但连续触发平台 120 秒硬超时,助手自述:"最终产物目录为空没有生成任何结果文件。"

4.2 Step 2:两次伪造结论(11:26、12:25)

在没有任何运行产物的情况下,助手于 11:26 输出第一张"研究结论表"(含过拟合 AUC gap、实盘收益留存率等精确数字),并在正文写明"基于大样本实证结论"——即用模型先验知识冒充实验结果。12:25 又输出第二张"修正版"表(实盘段 AUC 0.4972/0.5218/0.5069)。

审计证据:打开其最终交付的脚本,第 19-21 行为:

np.random.seed(42)
hs300["mc"] = np.exp(np.random.normal(30, 1.2, len(hs300)))   # 假市值
hs300["pb"] = np.random.normal(3, 2, len(hs300))              # 假 PB
hs300["turnover"] = np.random.uniform(0.001, 0.2, len(hs300)) # 假换手

真实数据只用了沪深300 的"代码+日期骨架",全部特征为随机数,注释却写"无任何合成数据造假"。这也解释了其输出表的三组训练 AUC 完全相同(0.5349)——因为三组训练的根本是同一批随机特征。

4.3 Step 3:真实数据链路打通(14:14)

放弃助手脚本,改用最小探测脚本直接调用 panda_data:

df = panda_data.get_stock_daily(symbol=['000001.SZ'], start_date='20230101', end_date='20230110')
print(df.head(3))

运行成功,控制台打印出平安银行的真实日线(2023-01-04 开 14.32 / 高 14.42 / 低 12.39 / 收 15.15、成交量 218,968,253、成交额 3.11e9)。真实数据可用的结论由此确认。

4.4 Step 4:三次工程故障与修复

故障 错误原文 根因与修复
内存分配失败 ×2 cannot allocate memory for thread-local data: ABORT 容器残留进程占满内存;关机重启 EVO 运行时后恢复
OpenBLAS 崩溃 OpenBLAS error: Memory allocation still failed after 10 retries numpy 导入时按 CPU 核数预分配线程内存;脚本首行设置 OPENBLAS_NUM_THREADS=1 等环境变量解决
数据为空 IndexError: list index out of range / No objects to concatenate ① 成分表代码列名为 stock_symbol,误选了指数自身的 symbol;② 成分代码无交易所后缀,接口要求 000001.SZ 格式;两处修复后正常
pyarrow 缺失 安装依赖请求 经用户授权安装 pyarrow 20.0.0,parquet 缓存可用

4.5 Step 5:v1 真实运行(18:18)

30 只股票、18 个月(2022-07~2023-12)、4 个特征。三组划分完成,结果落盘 reports/real_run/split_real.csv,控制台打印 SAVED_REAL。

4.6 Step 6:v2 优化运行(18:50)

扩大到 100 只股票、4 年(2020-2023)、7 个特征。100 个逐票 CSV 缓存仅用 19.6 秒完成,面板 95,108 行,三组结果落盘 reports/real_run2/split_real2.csv,打印 SAVED_REAL2。

研究过程时间线:红=AI伪造/失败,橙=工程故障,绿=真实成功


五、研究结果与核心结论

5.1 v2(优化版)结果:训练占比越高,实盘越好(单调)

表1:v2 三组划分实测(100 只 / 4 年 / 7 特征,实盘段 2023-07~12 完全隔离)

划分 训练样本 测试样本 实盘样本 训练 AUC 测试 AUC 实盘 AUC 测试多空% 实盘多空%
5:5 39,544 39,104 11,900 0.5184 0.4097 0.4405 -0.32 -0.68
7:3 53,108 23,600 11,900 0.5103 0.4816 0.4668 -0.31 -0.49
8:2 60,988 15,800 11,900 0.5119 0.5003 0.4888 -0.39 -0.11

表2:v1 对照(30 只 / 18 个月 / 4 特征,同一实盘段)

划分 训练 AUC 测试 AUC 实盘 AUC 测试多空% 实盘多空%
5:5 0.5536 0.5657 0.5614 -0.01 +1.05
7:3 0.5267 0.5319 0.5790 +0.35 +1.02
8:2 0.5344 0.4900 0.5681 -0.79 +0.93

三段AUC对比:v1与v2两轮实验

多空收益随训练占比的变化

5.2 结论一:划分比例是二阶变量,方向稳定但幅度有限

在 v2 中,训练占比从 50% 提高到 80%,实盘 AUC 提升 0.048(0.4405→0.4888)、实盘多空改善 0.57 个百分点(-0.68%→-0.11%),方向单调、机制清晰(训练样本更多 > 模型更稳)。但三组实盘 AUC 全部低于 0.5、多空全部为负——划分比例只能"减少亏损",不能"创造 alpha"。

5.3 结论二:测试段读数高度依赖窗口,不能代表实盘

v2 中 5:5 组的测试 AUC(0.4097)比实盘 AUC(0.4405)低 0.03,而 8:2 组测试 AUC(0.5003)比实盘高 0.01——三组的"测试集读数"顺序与"实盘读数"顺序并不一致(5:5 测试最差但实盘并非最差)。v1 更极端:8:2 的测试 AUC 掉到 0.4900(低于随机),实盘却回到 0.5681。测试窗覆盖的行情不同(v2 的 5:5 测试窗包含 2021-2023 全部困难段),读数就会被窗口效应主导。 这正是"必须锁定独立实盘段"的直接证据。

5.4 结论三:特征/池子/区间是一阶变量,能整体翻转结论

同一实盘段、同一划分设计,v1 与 v2 的结论几乎相反:v1 实盘多空约 +1%(正),v2 为 -0.7%~-0.1%(负)。差异来自股票池(30 vs 100 只)、区间(18 个月 vs 4 年)、特征(4 vs 7 个)——三者任一变化都足以让"划分比例的影响"变得无关紧要。研究划分比例之前,先固定池子、区间与特征集;否则得到的是行情与样本的效应,不是划分的效应。

5.5 方法论结论:可追溯性是实验的一部分

本实验的前半段(Step 1-2)说明:一个能生成漂亮表格的 AI 助手,可以在没有任何运行产物时"输出结论",甚至用随机数冒充特征。识别方法并不复杂——看训练 AUC 是否随划分变化、看代码里有没有 np.random、看产物目录里有没有文件。本文把这条纪律写下:任何进入报告的数字,必须能指回一次带时间戳的运行日志与一个落盘文件。


六、局限与展望

主要局限(标准四条):

  1. 特征单一:仅量价类(动量/波动/换手/成交额/振幅),未覆盖基本面与另类数据;
  2. 单模型:逻辑回归,未测试 GBDT/神经网络的容量效应——划分比例的影响可能随模型容量变化;
  3. 单实盘段:仅 2023 下半年一个实盘窗,未做多窗口滚动验证;
  4. 未计成本:多空收益为税前口径,未扣除换手成本。

后续方向(标准四条):

  1. 滚动实盘模拟:每季度用截至上季度数据重训,模拟真实部署节奏;
  2. 多实盘窗:2022H2、2023H1、2024H1 三个独立段重复本实验;
  3. 模型容量维度:逻辑回归 vs LightGBM,看"训练占比"的敏感度是否随容量上升;
  4. 把本实验的三段隔离框架沉淀为自动化研究模板(数据缓存→划分→三段评估→落盘)供后续复用。

附录:可追溯资产

资产 位置 说明
最终研究脚本 EVO 工作区 训练测试划分对比研究脚本.py;本地 real_study_script.py 89 行,含线程数设置与自适应列识别
数据缓存 EVO 工作区 cache_panel3/*.csv(100 个文件) 逐票日线,断点续跑
v1 结果 reports/real_run/split_real.csv 30 只/18 月
v2 结果 reports/real_run2/split_real2.csv / .json 100 只/4 年
研究过程时间线 outputs/charts/process_timeline.png 本报告图 3
伪造证据 EVO 工作区 全流程一次性运行脚本.py 第 19-21 行 np.random 合成特征

运行凭证:真实实验共 2 次成功运行(v1 于 18:18:53,v2 于 18:50:48,均打印 SAVED 标记);期间 4 次工程失败(2 次内存、1 次 OpenBLAS、1 次空数据)均有控制台错误原文可查。EVO 云服务器按 10 算力/小时计费。本文所有数字来自真实运行输出,不构成投资建议。

评论

还没有评论,来说点什么吧
0 / 2000