做建模的人十有八九在这个地方卡过一次:数据只有一份,切完发现验证集太小、指标抖动大,或者调完参再拿测试集看结果,心里发虚。这篇不讲概念定义,只讲怎么切、切多少、切完怎么自查,以及哪几种情况该反过来重新切。看完能立刻动手把手里那份数据分干净。
做建模的人十有八九在这个地方卡过一次:数据只有一份,切完发现验证集太小、指标抖动大,换个随机种子结果就变一个样;或者调完参再拿测试集看结果,心里发虚,因为那份测试集早就被自己瞄过好几遍了。这篇不讲概念定义,只讲怎么切、按什么思路定比例、切完怎么自查,以及哪几种情况该反过来重新切。
看完能立刻动手把手里那份数据分干净。前提是你已经有一份清洗过、去重过、并且知道每行代表什么实体的数据表;如果连实体维度都没搞清楚,先别切,切了也是白切。
先分清三份数据各自管什么,别切了用错
- 训练集
- 用来拟合模型参数,梯度更新只看它;它上面的指标只反映拟合程度,不代表泛化能力
- 验证集
- 用来挑超参、做早停、比模型结构;可以反复看,但看多了也会过拟合到它上面
- 测试集
- 只在最后用一次,用来给一个对外可交代的数字;用过就冻结,不能回头再调参
- 训练集负责拟合参数,验证集负责挑超参和早停,测试集只在最后用一次;三者一旦混用,指标就没有参考价值
- 常见误区是把验证集当第二训练集反复调、把测试集当验证集天天看,等价于让模型提前见过考卷
- 只有极少数场景可以省掉验证集:比如超参完全固定、不打算做早停和模型选择,此时才退化成只切两份
- 小样本场景下三份切完可能都不够用,这时要考虑交叉验证,而不是硬凑一个很小的测试集
常见比例分档:按数据量选,不按习惯选
比例这事没有标准答案,但有选择逻辑:数据量越大,验证集和测试集占的比例可以越小,因为绝对条数已经够撑住统计稳定性;数据量越小,比例越没有意义,因为真正起作用的是「验证集里有没有足够多的样本」。所以先看条数,再看任务类型。
| 数据量档位 | 切分思路 | 主要约束 |
|---|---|---|
| 几十万条以上 | 验证集与测试集各留一个很小的固定比例即可 | 保证每个集合的绝对条数够统计稳定,别抠比例 |
| 几千到几万条 | 最需要纠结的一档,验证集要能吃掉指标噪声 | 按任务定,分类和回归、类别是否平衡都不一样 |
| 几百条以内 | 不守比例,优先保验证集样本量 | 训练集少一点影响小,验证集少了指标没法信 |
| 类别不平衡 | 必须分层抽样,不能整体随机切 | 否则某个类可能在验证集里一条都没有 |
大规模数据具体怎么留、留多少,可以到 /training 看训练侧的一般做法和当时的口径;站内对各家模型在不同数据规模下的训练建议也有整理,数字以页面上当时的记录为准,这里不写死。
切分操作要点:顺序、随机种子与防泄漏
切分最容易出事的地方不是比例,是顺序。先去重、再清洗、最后切分,这个顺序不能反。先切再清洗,同一份噪声或同一条重复记录会同时出现在训练和测试两边,模型在测试集上表现好只是因为它见过
- 先去重和清洗把完全重复的行、同一实体的多条记录先处理掉;验证方式是统计去重前后每个集合的记录数变化,如果某集合掉得特别多,说明去重前就有泄漏
- 按实体维度分组同一个用户、同一篇文档、同一段连续时间切出来的片段不能跨集合分布;验证方式是抽几个实体,看它们是否只出现在一个集合里
- 固定随机种子并落盘把切分结果存成文件或表,训练时读同一份;验证方式是重跑一次训练,看指标是否完全一致
- 查分布切完后对类别标签、时间字段、来源字段各看一次分布;验证方式是两边分布差异明显就说明这次切分不可信
# 固定种子的切分思路(伪代码,按你的框架改)
# 1) 先按实体分组,保证同组不跨集合
# 2) 在组级别做随机划分,而不是在行级别
# 3) 把划分结果写入 split.csv 持久化
# 4) 训练脚本只读 split.csv,不重新随机切完先自查:四个信号判断分得对不对
- 验证集指标比训练集高很多,多半是切分泄漏或验证集太小,不是模型泛化好
- 同一模型换一次随机种子指标就大幅波动,说明验证集样本量不够,先扩验证集再谈调参
- 测试集结果和验证集结果差距明显,先怀疑两边分布不一致,回去查是否分层、是否按时间顺序
- 测试集用完一次就该冻结,后续任何改动都要重新划一份新的测试集,或者明确说明这份测试集已经被污染
这四个信号里,第一个和第二个出现的频率最高。很多人看到验证集比训练集好会先高兴,其实那通常是坏消息。要确认是不是泄漏,最直接的办法是去查训练集和验证集里有没有重叠的实体 ID,重叠就说明分组没做对。
这些情况下常规比例切法不适用
前面讲的按比例随机切,前提是样本独立同分布。一旦这个前提不成立,比例就不再是主要矛盾,切分方式本身要先改。
| 场景 | 为什么不能常规切 | 该怎么切 |
|---|---|---|
| 时序数据 | 随机切会让模型看到未来信息 | 按时间前后划分,训练在前、验证与测试在后 |
| 强分组结构 | 同组样本高度相关,跨集合就是泄漏 | 按设备、批次、患者等组维度切,比例次要 |
| 样本量极小 | 固定比例切出来的集合都不够稳定 | 交叉验证或留一法,代价是训练次数成倍增加 |
| 数据持续流入 | 一次切好的测试集会越来越不准 | 按时间滚动重建测试集,别永久复用同一份 |
如果你不确定自己属于哪一档,可以到 /tools/speed-test 先摸一遍手里数据的规模和字段分布,再决定切法;站内还有关于评测口径的说明,判断标准和当时的页面内容为准。
下一步把切分结果落盘、固定种子、冻结测试集这三件事做完,再回来调参;如果你需要对照不同任务下的划分建议,去 /training 看训练侧的整理,数字以页面上当时的记录为准。→常见问题
验证集一般留多少合适?
没有通用数字。判断标准是验证集里的样本条数够不够撑住指标稳定性:换一次随机种子指标就大幅跳,说明留少了。数据量大时小比例也够,数据量小时优先保条数而不是保比例,具体分档可以到 /training 对照训练侧的一般口径。
训练集、验证集、测试集能重复使用吗?
训练集和验证集可以反复用,这是它们的设计目的;测试集不行。测试集一旦用来做过任何决策,它就不再是干净的评估集。如果必须再调,就重新划一份新测试集,或者在结果里写明这份测试集已被污染,别把它当成最终结论。
先切分还是先清洗?
先清洗、去重,再切分。反过来做的话,同一条重复数据可能同时落进训练和测试两边,模型等于提前见过考题,指标会虚高。去重最好在切分前按内容指纹做一遍,切完后再按实体维度查一次有没有跨集合的重复。