数据集:划分原始数据集#
任何一个像样的软件工程项目,都会把相当大的一部分精力花在测试上。同样的道理,我们强烈建议你对 ML 模型也做测试,以确认它的预测到底是否正确。
训练集、验证集与测试集#
你应当用一组不同于训练样本的例子来测试模型。本节后面「测试集的其他问题」一节会展开说明这一点:在新样本上测试,比在训练用的同一批样本上测试,更能说明模型是真的好用,还是只是把做过的题背下来了。
MLWM: 我们在完成模型训练以后,都会在测试集上对模型的泛化能力进行评估。
那这些"不同的样本"从哪儿来?在机器学习的传统做法里,答案是拆分原始数据集。于是你可能会想当然地认为,把原始数据集拆成两半就够了:
训练集(training set):模型用来训练的那部分数据。
测试集(test set):用来评估训练好的模型的那部分数据。

练习:检验你的直觉#
假设你用训练集训练、用测试集评估,如此反复了好几轮。每一轮,你都依据测试集的结果去调整超参数和特征集。你能看出这种做法有什么问题吗?(只选一个)
A. 大量重复这一过程,可能导致模型隐式地拟合测试集的特殊之处
B. 这种做法没问题。毕竟你是在训练集上训练、在独立的测试集上评估
C. 这种做法在计算上效率不高
D. 每轮测试之后都不要改动超参数或特征集
把数据集拆成两半是个不错的主意,但更好的做法是把它拆成三份。除了训练集和测试集,第三份是:
- 验证集(validation set):在模型训练的过程中,用它对模型做初步测试。

验证集用来评估训练集跑出来的结果。当反复使用验证集的结果都表明模型预测得不错时,再动用测试集给模型做一次复核。
下面这张图展示的,正是这样一套工作流。
图中的「调整模型」,指的是对模型做任何层面的改动——改学习率、加减特征,甚至从头重新设计一个模型,都算在内。
注意: 当你对训练集里的某个特征做了变换,验证集、测试集以及真实世界的数据都必须做同样的变换。
图 10 展示的流程固然理想,但即使照着它做,测试集和验证集也会随着反复使用而「磨损」。也就是说,你越是反复拿同一批数据来决定超参数怎么设、模型怎么改,对模型在新数据上表现良好的信心就越小(因为在整个过程中测试集有潜移默化地被当成训练接在使用了)。
正因如此,收集更多新数据来更新测试集和验证集是个好主意。
练习:检验你的直觉#
你把数据集里的样本全部打乱,然后拆成训练集、验证集和测试集。但测试集上的损失值低得离谱,低到让你怀疑是不是出了什么差错。问题可能出在哪里?
A. 测试集里有很多样本是训练集样本的重复
B. 训练和测试是不确定的,有时候纯属运气,测试损失会低得惊人
C. 纯属运气,测试集刚好包含模型表现很好的样本;样本洗得很彻底,所以极不可能
测试集的其他问题#
正如上一道题所展示的,重复样本会影响模型的评估结果。
因此,把数据集拆成训练集、验证集和测试集之后,要删掉验证集和测试集里那些与训练集样本重复的例子。评测一个模型,唯一公平的方式是拿新样本去测,而不是拿重复样本去测。
举个例子。假设有个模型,用邮件标题、正文和发件人地址作为特征,来判断一封邮件是不是垃圾邮件。你按 8:2 的比例把数据拆成训练集和测试集。训练结束后,模型在训练集和测试集上都达到了 99% 的精确率。测试集上的精确率高得不太正常,你回头再看看数据,发现测试集里有很多样本就是训练集样本的副本。问题出在:你拆分数据之前,没有把数据库里同一封垃圾邮件的重复条目清理掉。你不知不觉地在一部分测试数据上做了训练。
总的来说,一个好的测试集或验证集,需要同时满足以下所有条件:
规模足够大,能给出统计显著的测试结果。
能代表整个数据集。换句话说,别挑一个特征与训练集不一样的测试集。
能代表模型在真实业务中将会遇到的真实数据。
不包含任何与训练集重复的样本。
三道题小测验#
第1题: 只有一份样本数固定的数据集,下列哪条说法成立?
A. 测试集样本数必须大于验证集或训练集
B. 每个用于测试的样本,都是少一个用于训练的样本
C. 测试集样本数必须大于验证集
第2题: 测试集里的样本足够多,测试损失也很低,可模型在真实世界中的表现却很糟。你应该怎么做?
A. 在同一个测试集上重测,结果可能只是一次异常波动
B. 找出原始数据集与真实数据的差异
第三题: 测试集里应该放多少样本?
A. 足够多,能给出统计显著的测试结果
B. 至少占原始数据集的 15%
关键术语:
测试集
训练集
验证集