开始前,会这些就够了
- 知道训练集用于学习,测试集用于最终评估
- 理解平均数
遇到不熟悉的词,先看这 5 个解释
- 训练
- 利用数据和既定目标来调整模型参数的过程。在常见神经网络中,程序先计算输出与目标之间的差距,再按更新规则反复调整,希望对新数据也有用。
- 数据泄漏
- 建模或选择方案时,用上了真实预测时不该得到的信息,例如测试集统计量、未来才产生的字段或重复出现的答案。这样评估可能显得很好,却不能代表面对新数据的能力。
- 评测
- 用事先确定的样本、任务和评分规则,检查模型或整个系统能否满足要求的过程。既可检查答案,也可检查工具操作和最终状态,结果要连同测试条件一起理解。
- 分组验证
- 评估模型能否处理新对象时,把同一用户、设备或文档的记录作为一组,整组放进训练或验证的一边,避免同一个对象同时出现在两边。
- 时间切分
- 模拟用过去预测未来时,按记录发生的先后划分数据:较早的一段用于训练,较晚的一段用于验证或测试,而不是把所有日期随意打散。
假设你要在订单创建时预测是否会退货。离线表里有一列“退款完成时间”,模型用上它之后分数非常好。问题是,这列信息在下单时还不存在。即使训练行和测试行完全分开,测试仍在考一个现实中拿不到答案提示的任务。这是虚构案例,但它点出了数据泄漏的核心。
泄漏不一定是有人故意把答案复制进输入。只要建模时用了预测当下不该获得的信息,评估就可能过于乐观。检查重点应是每条信息什么时候产生、谁在什么步骤使用了它,而不只是文件名里有没有 train 和 test。
字段存在,不代表当时可用
回看一张整理好的历史表,很容易忘记其中的字段来自不同时间。下单时能获得商品和数量,却不能获得将来是否退款的结果。给每个输入字段加上“最早可用时间”,再与要作预测的时间比较,才能把事后信息找出来。用于评价的最终结果当然可以稍后得到,但不能作为当时的输入。
也要检查同一个对象是否以多条记录出现。如果任务是预测从未见过的新用户,训练集和测试集混入同一用户的近似记录,可能让模型靠熟悉的个人特征过关。如果任务本来就是预测已知用户的未来行为,切分目标又不同;分组不是万能规定,必须先写清希望推广到谁、哪个时间段。
没有标签,求平均也可能提前看了试卷
预处理也会从数据中学习数值。例如把每个数减去平均值,需要先确定平均值取自哪里。下面用三个训练值和一个测试值演示:仅用训练值求平均,与把测试值也算进去,会让同一个训练数得到不同的中心化结果。差别出现于模型训练之前,所以不能靠之后再切一份测试文件来消除。
这个小程序只证明测试数据影响了预处理参数,没有训练分类器,也不声称这一次平均值变化必然提高分数。泄漏可能以多种方式改变结果;其根本问题是评估没有保持原先规定的信息边界。缺失值填补、特征选择和降维等会学习参数的步骤,也要检查拟合数据来自哪一部分。
from statistics import mean
train = [10.0, 12.0, 14.0]
test = [1000.0]
train_mean = mean(train)
leaky_mean = mean(train + test)
print(f"train-only mean={train_mean:.1f}")
print(f"with-test mean={leaky_mean:.1f}")
print(f"same training value: {12.0 - train_mean:.1f} vs {12.0 - leaky_mean:.1f}")
怎样运行:Python 3.10+;保存为 leakage_mean.py,在该目录运行 python leakage_mean.py。只用标准库,无需联网。
运行后对照结果
train-only mean=12.0
with-test mean=259.0
same training value: 0.0 vs -247.0把切分、拟合和评估的顺序写清
通常先按任务需要划分数据,再只在训练部分拟合预处理参数和模型。验证、测试和线上输入使用训练时学到的同一套转换规则。scikit-learn 中 fit 表示学习参数,transform 表示按已学规则转换;把这些步骤放进正确使用的 Pipeline,可减少交叉验证时把验证折提前用于拟合的失误。
管道不会自动知道“退款完成时间”来自未来,也不会替你决定用户应如何分组。时间预测要让评估符合先见过去、后看未来的使用方式;新对象预测则要避免同一个对象横跨训练与评估。具体是否要留时间间隔、如何处理重复记录,仍取决于数据产生过程。
模型和阈值可以用验证集选择,最终测试集用于检验已选方案。如果反复查看测试成绩,再据此改特征或参数,它也逐渐参与了选择。记录切分规则、拟合范围与查看测试结果的次数,远比只保留最高分更有帮助;发现泄漏后应重做干净评估,不能把旧分数继续当成未知数据上的能力。
记住这三点
- 用预测时拿不到的信息,可能让离线评价高估实际能力。
- 预处理的拟合范围也属于训练边界,测试数据不能提前参与。
- 分组、时间切分和管道各解决一部分问题,仍须检查字段来源。
别把例子用过头
- 退款案例完全虚构;本地代码只展示均值受影响,没有制造或测量模型准确率。
- 固定的逐条无状态转换与需要拟合参数的转换应区分,不能见到预处理就一概判定泄漏。
- 如何分组或按时间评估取决于目标使用场景,不是所有数据都套同一切分方式。
自己试一小步
怎样为一个预测任务画出“不准提前知道什么”的时间线?
- 选择自拟的退货或设备维护任务,写明预测发生的时刻。
- 列五个候选字段,分别标出产生时间与是否依赖最终结果。
- 画出切分、预处理拟合、模型选择和最终测试的执行顺序。
做到这些,就算完成
- 输入字段在预测时确实可获得。
- 预处理参数的拟合范围明确。
- 重复对象、时间先后和最终测试反馈都在检查范围内。
查原始资料
想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。
- scikit-learn:常见错误与数据泄漏 (新标签页)↗
只在训练部分拟合预处理、先切分再拟合,以及 Pipeline 的使用边界。
- scikit-learn:分组与时间序列交叉验证 (新标签页)↗
新组泛化时的分组隔离、时间序列的评估顺序,以及反复用测试集调参的风险。
找一份资料继续练
先选一项,按下面的范围继续学;不必从头读完整门课程。
机器学习速成课程:用图和小练习理解模型 (新标签页)↗
只读“数据集、泛化和过拟合”,给一个预测任务列出数据何时产生、在哪一步使用,并留出最后才查看的测试数据。
查看学习准备与访问说明 →scikit-learn:同一个人的数据,该分到哪一边 (新标签页)↗
交两份虚构记录的切分清单,分别检查组不重叠和时间顺序。
查看学习准备与访问说明 →