模型跑出来在训练数据上好看,换个数据集就垮,八成是划分这一步没做对。这篇不讲模型原理,只讲三件事:三条数据各自干什么活、按什么顺序切、比例调大调小会牵扯到什么。看完你至少能判断自己手上的切分方式合不合理,以及为什么要这么切。
模型在训练数据上分数漂亮,换一份数据就崩,八成是划分这一步埋了坑。这篇不讲模型结构,只讲三件事:三条数据各自干什么活、按什么顺序切、比例调大调小会牵扯到哪一头。看完你至少能判断自己手上的切分方式合不合理,以及为什么不合理。
入门阶段最容易犯的错,是把评估指标当成模型能力本身。指标只是在某一份特定切分上的一次测量,切分方式一变,数字就跟着变。所以先搞清楚每一份数据的职责,再谈比例,才不会来回返工。
三条数据各自干什么活,先分清再谈比例
训练集是模型真正用来学参数的那部分,每轮迭代都拿它更新权重。验证集不参与参数更新,只用来做选择:选超参数、选特征、决定哪一轮停下来。测试集只在最后用一次,代表你对真实场景表现的估计。
- 训练集
- 参与参数更新,模型反复看,指标天然偏高
- 验证集
- 不更新参数,用于选超参和早停,可以多轮使用
- 测试集
- 只在定稿时跑一次,用来估真实表现,用过就封存
- 三条数据的角色不能互换,用测试集反复调参等于把它变成验证集,最后报出来的分数会虚高;
- 验证集可以一轮轮用,测试集原则上用一次,模型改完要重新换一份;
- 数据量很少时,可以只分训练和验证先推进,等方案定下来再单独留一份锁住的测试集;
- 如果团队里没人负责守住测试集,就把它物理隔离,放在另一个目录或另一个人手里。
划分顺序:先锁测试集,再切验证集
推荐顺序是先切出测试集并封存,再从剩下的数据里切验证集,最后剩下的全部当训练集。这样做的好处是数据分布只被切两次,不会因为反复随机切分而让某一份偏斜。反过来先切训练集,验证和测试往往会被同一批难样本污染。
- 第一步 锁测试集从全量数据里按比例切出一份,立刻封存,只记录划分方式和随机种子,不参与任何调参。
- 第二步 切验证集从剩下的数据里切出验证集,分类任务要按类别分层抽样,避免某个类别一条都没进验证。
- 第三步 核对分布对比三份数据的类别比例、特征均值、时间跨度,差异明显就换种子重切,别硬上。
- 第四步 记录留档把划分脚本、种子、各类样本数写进一个文件,后面复现和对比才有依据。
顺序之外还有两条硬规则。时序数据必须按时间切,绝不能随机打乱,用未来信息预测过去是最常见的隐性泄漏。同源样本要整组进同一份,比如同一个用户、同一台设备的多条记录,拆到两边就等于把答案提前告诉了模型。
比例调大调小,影响的是哪一头
没有万能比例,只有看你的数据总量和任务难度。总量大、任务简单时,验证和测试占比可以压得很低;总量小的时候,比例怎么调都紧张,问题不在比例而在评估方法。
| 调整方向 | 直接后果 | 什么情况下不适用 |
|---|---|---|
| 训练集变大 | 模型见过的样本多,指标更稳 | 数据本身有噪声时,多喂反而记住噪声 |
| 验证集变小 | 早停和选超参噪声变大,换个种子结果就变 | 数据集极大且指标方差本来就小时影响有限 |
| 测试集变小 | 指标置信区间变宽,几分差距说明不了问题 | 只做趋势对比、不做结论发布时可以接受 |
| 整体偏小 | 三份都不够用,评估结果不可信 | 改用交叉验证后,独立测试集仍要单独留一份 |
想要横向比较不同划分方案下的实际影响,可以到 /rankings 看当时的评测结果,具体数字以页面实时显示为准。别把某一份切分上的得分当成模型的固有属性。
划分做完,先跑一遍泄漏自查
划分方式合理,不代表没有泄漏。泄漏的典型表现是离线指标远好于上线表现,而模型本身没变。切分完先花十分钟做下面四项自查,比调参划算得多。
- 查重复样本:同一条数据或它的改写版本同时出现在训练和测试里,指标会明显偏乐观;
- 查特征穿越:用到了预测时刻之后才知道的字段,比如用后续状态去预测先前行为;
- 查预处理顺序:归一化、填充、编码的统计量只能在训练集上算,再套到验证和测试集;
- 查时间窗口:验证和测试的时间范围必须晚于训练集,不能有重叠;
- 查分组归属:同一用户或同一批次的数据要整组落在同一份里。
自查通过后,把划分方式、随机种子、类别分布记下来。想进一步核对不同工具链在数据切分上的支持情况,可以到 /tools/speed-test 和 /tools 对照当时的条目。
数据太少,什么时候该换成交叉验证
当独立验证集小到每次挑出的超参都不一样时,说明单次划分的方差太大,该换成 K 折交叉验证。做法是把训练数据切成 K 份,轮流拿其中一份当验证,其余当训练,最后取平均。这样每条数据都当过验证样本,评估更稳。
| 场景 | 建议做法 | 注意点 |
|---|---|---|
| 样本量中等 | 一次划分训练验证,另留测试集 | 固定随机种子,记录分布 |
| 样本量很少 | 分层 K 折交叉验证 | K 太小时每折波动大,K 太大开销高 |
| 类别极不平衡 | 分层抽样或分层 K 折 | 保证每折类别比例接近整体 |
| 时序数据 | 按时间滚动切分 | 不能随机打乱,验证段必须在训练段之后 |
交叉验证得到的只是平均表现,不是最终指标。方案定稿后仍然要留一份从未参与训练的独立测试集做最终估计,否则你报出的数字没有可信度支撑。
划分不是预处理里的小步骤,它决定了你后面看到的每一个数字代表什么。下一步把你手上的划分脚本对照上面的顺序和自查清单跑一遍,需要参考评测口径时到 /rankings 核对当时的数字。→
常见问题
训练集、验证集、测试集到底按几比几来分比较合适?
没有一个通用数字。数据量大、任务简单,验证和测试可以各留很小的比例;数据量小就得匀出更多给验证。先保证测试集足够给出稳定估计,再决定验证集大小,剩下的都给训练。不要把某组比例当成硬标准,具体到你的任务要看样本量和指标波动。
把训练集比例调高,模型效果一定会变好吗?
不一定。训练样本多了确实能提升拟合能力,但如果验证集被压得太小,选超参和早停就会变得很不稳,你甚至看不出模型到底是变好还是只是随机波动。反过来训练集太小则容易欠拟合。这两头的取舍没有通解,看的是验证曲线是否稳定。
验证集和测试集能不能用同一份?
不建议。一旦用同一份数据反复调参,你对它的了解就渗进了模型选择里,它报出来的分数会偏乐观,无法代表未知数据。哪怕数据紧张,也尽量在最后阶段另留一份从未参与调参的数据做最终评估,否则等于没有测试集。