← 返回文章库

标准化没有看测试标签,为什么仍可能泄漏测试信息

2026-10-24 · L5

即使完全没看测试标签,标准化仍可能泄漏:训练均值、分位点或填补值若由测试特征参与拟合,就已经把未来的分布信息带入了模型。解决办法是逐步保存参数由哪些行、哪个处理阶段拟合,再固定参数变换测试数据;仅记录一个train_only开关不够。

八行特征和三条处理路径

本例构造一列无量纲特征,前五行为训练,第六至八行为后续测试。原始值依次为1、缺失、3、9、100、缺失、200、300。不存在标签列,因此后面出现的参数差异不可能归因于偷看测试标签。缺失由None表示,不与数值零混用。三条路径分别是正确训练拟合、错误全八行拟合,以及仍只用训练但改变分位点拟合顺序的对照。

正确路径先以训练非缺失值求中位数,再填补训练和测试;随后在填补后的训练向量拟合百分之二十与八十分位点,将两边都截到该区间;最后在截断后的训练值拟合均值和总体标准差。测试始终只接受transform,不回写任何参数。分位点采用排序位置(n-1)q的线性插值,标准差分母用n,全部算完才为表格舍入。

路径拟合行填补中位数下分位点上分位点截断后均值总体尺度
train_only[1, 2, 3, 4, 5]62.627.29.569.11736804
wrong_all[1, 2, 3, 4, 5, 6, 7, 8]54.55.416068.660.86063999
order_change[1, 2, 3, 4, 5]62.245.413.1216.31764689

参数血缘不能只写一个日期范围

正确路径的中位数来自原始训练非缺失向量[1,3,9,100],结果为6;填补后训练向量[1,6,3,9,100]重新排序,分位点为2.6与27.2。截断后得到[2.6,6,3,9,27.2],它的均值为9.56,总体尺度约9.11736804。这个顺序意味着后一个参数不仅依赖训练行号,还依赖前一步的中位数和截断定义。

可以把血缘写成四段有向关系:原始训练非缺失行指向中位数,中位数与原始训练行共同指向填补结果,填补训练结果指向上下分位点,截断训练结果指向均值和尺度。测试原始行只指向测试填补、测试截断与测试缩放结果,没有任何反向箭头回到拟合节点。没有画图软件也能按这个箭头清单核查,每一个fit节点都应附输入身份和上游参数版本。

训练拟合路径逐行结果:

行原始填补后截断后缩放z
1112.6-0.7633782
2空(null)66-0.39046356
3333-0.71950589
4999-0.06142123
510010027.21.93476889
6空(null)66-0.39046356
720020027.21.93476889
830030027.21.93476889

错误全样本路径逐行结果:

行原始填补后截断后缩放z
1115.4-1.03843798
2空(null)54.554.5-0.23167683
3335.4-1.03843798
4999-0.97928645
51001001000.51593279
6空(null)54.554.5-0.23167683
72002001601.50179163
83003001601.50179163

先对观测值拟合截断点的顺序对照逐行结果:

行原始填补后截断后缩放z
1112.2-0.66921414
2空(null)66-0.43633742
3333-0.62018746
4999-0.25248739
510010045.41.97822641
6空(null)66-0.43633742
720020045.41.97822641
830030045.41.97822641

没有标签的全样本处理为何仍不合法

错误路径把测试中的200、300放进中位数拟合,使填补值从6变为54.5;全样本上下分位点变成5.4和160,均值变为68.6,尺度约60.86063999。第六行本来缺失,同一行经过不同历史定义得到不同z;第七、八行本来很高,在正确路径中都被训练上限截住,错误路径则借助它们自己的分布把上限向外推。

这些变化不保证每次都让回测更好,有时也会让成绩变差。泄漏的判定看信息是否可得,不能看结果是否漂亮。某个模型对整体线性缩放恰好不敏感,也不能为全样本填补和非线性截断开脱;参数本身已经越界,换模型或缺失结构后后果会变。本文没有训练分类器,因此也不声称这些z变化能提高多少准确率。

条件对照order_change仍只使用训练行,却先对原始非缺失值拟合分位点,再按中位数填补。它得到2.2与45.4,尺度约16.31764689,与正确路径不同。这条路径不是测试泄漏,而是另一套预处理定义;如果事前就冻结,并在所有折一致执行,可以作为候选流程。不能把所有数值差异统称泄漏,也不能把两种顺序的参数互相拼接使用。

如何把核对落实到每次fit

开始一折前,保存原始数据版本和训练、验证、测试行身份。拟合填补器时输出参与计算的非缺失行,拟合截断器时说明用的是填补前还是填补后向量,拟合缩放器时标明总体或样本标准差。随后保存完整参数对象供后续transform使用,而不是在预测函数里临时调用均值。每条预测还要保存所用参数对象的身份,才能追到当时的训练边界。

如果一折训练全部缺失,中位数不存在;如果截断后所有训练值相等,尺度为零。遇到这些输入应预先定义拒绝该特征、输出固定零并另加缺失标记等政策,不能把除零变成NaN一路传下去。当前八行没有触发零尺度,模型在尺度为零时将z写为null,明确表示未定义,读者不能把它当作正常缩放结果。更换缺失政策时,旧折和新折要各自保留版本。

滚动研究中的“到今天重新fit”也是一次新模型。过去预测必须继续引用当时参数,不能用今天更新后的均值回写历史,再称它为历史实时预测。若财务数据后来修订,训练边界正确仍不等于原始数据当时可得,应另存发布时点和修订版本。这份血缘表覆盖的是预处理层,不能替代数据源的时点审计。

方法来源支持到哪一步

scikit-learn预处理与泄漏说明支持先划分、仅训练fit、后续使用相同transform的做法,涉及StandardScaler、SimpleImputer等变换。本文没有调用这些库;线性分位点、截断顺序和八行输出均由明示公式自算。原文不能为本例的分位比例背书,更不能证明处理后的特征有投资价值。把参数血缘交完整,是为了让下一位复核者能从原始八行重建每一步,而不是只相信最终一列看起来正常的数字。

怎样辨认参数版本串用

同样的训练起止日也可能对应不同参数版本,因为缺失政策、分位点插值和先后顺序都能改变结果。因此参数对象至少保存步骤名、上游对象身份、参与行身份、公式口径及输出值。若测试第七行使用训练中位数,却误搭全样本截断上限,最终z可能落在看似正常的区间,单靠检查有限数值无法发现。复核应逐节点验证来源,而不是只验证最终特征没有缺失。可以取第六行缺失样本作为追踪探针:它的填补值最直接暴露参数来自哪一侧,也容易检查缓存对象是否被后续折覆盖。

继续核对研究流程时,可回到时序交叉验证母题;遇到相邻任务,再分别查看面板数据gap按日期切分、嵌套时间序列验证调参。本文的滚动验证工具链接仅作基础流程说明,新增审计和统计计算由本页独立表格与模型交付。

道积君编辑组,AI辅助编写与核算。本文为构造教学实验,来源说明方法,数字由明示输入计算,不代表真实策略、收益预测或统计审定。

复算资料

本篇编号DJ4-058。下载Python复算脚本(文本)与构造输入输出JSON,按编号核对本篇。脚本改存为.py后可用Python标准库运行,数据不是实际用户记录。

这个页面有问题?

提交时会附带当前页面地址和浏览器信息,帮助我们定位问题。不填联系方式即为匿名。