ML学习笔记 #08 数据集划分与误差分析
本文最后更新于:2022年11月16日 中午
如何在实际情形中高效地使用机器学习模型?如何调参优化一个现有的模型?什么时候才需要获取更大的数据集?什么时候需要寻找更多的特征?什么时候需要改变正则化程度?
本节将介绍常用的机器学习诊断法(Machine Learing Diagnostic),高效地评估某种算法,并指导如何改进这个模型。
数据集划分
在以往的实验中,我们把所有数据集拿来训练一个模型,同时为了评估假设函数,我们还会用它进行测试。这显然不是一个好的做法,因为即便准确率很高,那也可能存在过拟合现象。
正确的做法应该是将数据集划分为训练集(Training Set)独立的测试集(Testing Set),通常划分比例为 \(7:3\)。在训练集上收敛后,再到测试集进行测试,最终的准确率作为模型的准确率。这样做才能确保模型在不同数据上的泛化能力。
进一步,如果模型中含有超参数,例如正则化的参数 \(\lambda\) 或神经网络的层数 \(L\),这是需要我们人工设置的。通常我们会设置多组参数对照,分别在训练集中训练到收敛,再在测试集中测试并选取最好的结果,也称交叉验证(Cross Validation)。于是又产生了同样的问题:测试集上的准确率不能代表模型的准确率。即:对测试集最优的超参数不一定对其他数据具有相同的泛化能力。
为此我们继续引入验证集(Validation Set),即用验证集而非测试集去调参,最后在测试集上跑结果。通常划分比例为 \(6:2:2\),测试集自始至终不参与模型的建立。这与常见的数据挖掘比赛的赛制异曲同工,只不过赛中测试集固定,只有验证集需要手动划分。
值得一提的是,如果我们在训练过程中加入了正则项,那么在计算模型的代价函数(误差)的时候应该去掉正则项。这是因为加入正则项的目的是训练出一个更为合理的参数 \(\theta\),而为了评价这个参数 \(\theta\) 的好坏,原本的代价函数才是真正的代价。
举个例子,当我们想知道正则化参数 \(\lambda\) 取 \(0,1,2,\cdots, 9\) 中那个较好时,需要用训练集训练出 10 个不同的模型,并在验证集上交叉验证,此时的代价函数就不应该包含正则化。
高偏差与高方差
在前文 ML学习笔记 #5 过拟合与正则化 中,我们提到欠拟合(Under-Fitting)对应的模型是高偏差(high bias),而过拟合(Over-Fitting)对应的模型是高方差(high variance)。
以多项式回归为例,随着多项式系数的增加,我们从欠拟合逐渐过渡到过拟合,训练集上的代价函数 \(J_\text{train}(\theta)\) 逐渐减小,而验证集上的代价函数 \(J_\text{valid}(\theta)\) 先减小后增大,形成下图所示情况:
观察发现:当 \(J_{\mathrm{valid}}(\theta )\approx J_{\mathrm{train}}(\theta )\) 时,模型处于欠拟合(高偏差);当 \(J_{\mathrm{valid}}(\theta )\gg J_{\mathrm{train}}(\theta )\) 时,模型处于过拟合(高方差)。实际中我们也可以通过计算误差来分析模型。
学习曲线 | Learning Curve
此外,作出学习曲线也有利于帮助我们分析模型拟合情况。学习曲线是误差函数关于「训练集规模」的曲线。
如果我们尝试用一条直线来拟合曲线数据,显然,此时模型欠拟合,无论训练集有多么大误差都不会有太大改观:
当训练集规模很小时,\(J_\text{train}(\theta)\) 比较小,而 \(J_\text{valid}(\theta)\) 很大;随着训练集规模的增大,\(J_\text{train}(\theta)\) 迅速增大,\(J_\text{valid}(\theta)\) 减小,但是减小的幅度不大;最后,当训练集规模很大时,二者基本相当且都比较大。
而如果我们使用一个非常高次的多项式模型,并且正则化非常小,显然,此时模型过拟合。可以看出,当交叉验证集误差远大于训练集误差时,往训练集增加更多数据可以提高模型的效果:
当训练集规模很小时,\(J_\text{train}(\theta)\) 很小,而 \(J_\text{valid}(\theta)\) 很大;随着训练集规模的增大,\(J_\text{train}(\theta)\) 增大,但是增大的幅度不大,而 \(J_\text{valid}(\theta)\) 减小,但是减小的幅度也不大;最后,当训练集规模很大时, \(J_\text{train}(\theta)\) 较小,但 \(J_\text{valid}(\theta)\) 较大。
学习曲线还可以用于判断一个模型的潜能。如果一个模型随着数据量增大,效果成指数形式上升,则说明增大数据量可能会达到更好的效果。但如果成对数形式上升,则说明不具有数据潜力。
神经网络的方差和偏差
在文章的开头,我们提出了一个问题:什么时候需要寻找更多的特征?显然现在我们已经知道答案:当模型过拟合时,很可能是因为特征及参数过多导致模型将训练集完全拟合,因此可以尝试减少特征的数量;同理,当模型欠拟合时,可能是现有的特征太简单、不足以刻画训练集,因此最好尝试获得更多的特征。
此外,使用神经网络也可以免于复杂的特征工程,只需将原始特征作为输入层,通过网络自动适应即可。但是难道越复杂的神经网络就越好吗?神经网络也会出现过拟合。
对于一个较小的神经网络,可以类比为参数较少的情况,容易导致高偏差和欠拟合;而对于较大的神经网络,类比于参数较多的情况,容易导致高方差和过拟合。虽然后者计算代价比较大,但是可以通过正则化手段来减少其过拟合程度,并且通常会取得比前者更好的效果。
例如神经网络中的隐藏层的层数的选择、各层的宽度设置,通常从一层、较窄的网络开始,逐渐增加层数和宽度,并将数据集划分为训练集、验证集和测试集,针对不同规模的网络进行验证,选择验证集代价最小的模型作为最终模型。
误差分析 | Error Evaluation
除了通过观察学习曲线判断拟合情况,还可以人工检查验证集预测出错的样本(Bad Cases),分析这些错误样本是否存在某种系统化的趋势。例如,某个类别总是被预测错误、某些样本预测误差最大等,从而思考怎么改进分类器。通过加入不同特征、尝试不同模型、设计不同网络结构来针对性训练。
因此,快速开发出一个不完美但可用的模型是很有必要的,它可以指导你的下一步该怎么走,比起花费大量时间思考显然高效很多。当然,如果能有一个数值化的评价指标,那实验的进度也能大大加快。
类偏斜的误差度量 | Skewed Classes
过去我们常用预测的准确率(Accuracy)或错误率(Error Rate)来评价一个分类模型,既适用于二分类任务,也适用于多分类任务。然而,Accuracy 却无法满足所有的分类需求,例如以下情形:
- 癌症患者识别任务,患者为正例,正常人为负例。显然患者的比例远小于正常人的比例,例如 \(1\%\),如果我们将所有样例都识别为正常人,那么该模型的 Accuracy 将高达 \(99\%\),但显然这不是我们想要的结果。
- 垃圾邮件识别任务,垃圾邮件为正例,正常邮件为负例。与患者识别类似,垃圾邮件的比例较低,而人们却更关心有多少垃圾邮件被识别了出来,而不是 Accuracy。
这些任务的特点是类别分布极不均衡,即存在类偏斜问题(Skewed Class),在多分类任务中也被称为长尾分布问题(Long Tailed Distribution)。在 IR学习笔记 #5 检索系统评价 曾提及混淆矩阵(Confusion Matrix),下面我们探讨更一般化的情形:
/ | 实际为正例 \(P\) | 实际为负例 \(N\) |
---|---|---|
预测为正例 \(P\) | \(TP\) | \(FP\) |
预测为负例 \(N\) | \(FN\) | \(TN\) |
定义精确率(Precision)也称查准率、精度,从预测结果角度出发,所有预测为正例 \(P\) 的样本中,实际正例的占比: \[ Precision\triangleq \frac{TP}{TP+FP} \] 定义召回率(Recall)也称查全率,从实际结果角度出发,所有实际为正例 \(P\) 的样本中,被预测为正例的占比: \[ Recall\triangleq \frac{TP}{TP+FN} \] 此外还可以得到与 Precision 相对的误报率(Fallout),与 Recall 相对的漏识率(Miss)。
精确率和召回率的权衡
Precision 和 Recall 通常是一对矛盾、此消彼长的性能度量指标。一般来说,Precision 越高时,Recall 往往越低,反之亦然。还是以癌症患者识别任务为例,假设我们的算法会输出一个 \([0,1]\) 的概率值,默认以 \(0.5\) 作为阈值。
如果将一个正常人诊断为癌症患者,则会使其承担不必要的治疗。因此我们可以在保持模型不变的情况下提高阈值,如 \(0.7\) 或 \(0.9\),进而提高精确率——即只在非常有把握的情况下诊断为癌症。然而,如果漏识了一个潜在的癌症患者,带来的灾难可能是更巨大的。因此我们也可以降低阈值,进而提高召回率——即让所有潜在病人都得到进一步地检查。
为此,我们定义了一个统一的指标来衡量模型的召回率与精确率,即: \[ \mathrm{F} \text {-score }=\left(1+\beta^2\right) \frac{\text { Precision } \cdot \text { Recall }}{\beta^2 \cdot \text { Precision }+\text { Recall }} \] 其中 \(\beta\) 越大表示越强调精确率,反之则强调召回率。当 \(\beta=1\) 时,得到我们最常用的 \(\mathrm{F1}\) 值: \[ \mathrm{F1} \text {-score }=2 \cdot \frac{\text { Precision } \cdot \text { Recall }}{\text { Precision }+\text { Recall }} \] 对于一个模型来说,如果想要在精确率和召回率之间取得一个较好的平衡,最大化 \(\mathrm{F1}\) 值是一个有效的方法。
如果我们有多个模型,如何利用精确率和召回率评估模型之间的优劣呢?通过固定模型后调整阈值大小,我们可以得到一系列精确率和召回率并绘制成一条曲线,而这条曲线就被称为 PR-曲线( Precision-Recall Curve)。
在 PR Curve 的基础上,可以曲线下面积(Area Under the Curve, AUC)来得到一个模型整体的评估值,从上图中可以看出,高 AUC 值也就意味着高精确率和高召回率,也就意味着模型的效果越好。
多分类的精度和召回率
在 ML学习笔记 #4 逻辑回归:二分类到多分类 中,我们介绍到对于 \(N\) 分类问题,可以将其转化为 \(N\) 个二分类问题,并将每个类别单独视为「正例」,其他类型视为「该类别的负例」。
此时的混淆矩阵可以这样统计:
/ | 实际为类 1 | 实际为类 2 | 实际为类 3 |
---|---|---|---|
预测为类 1 | 43 | 5 | 2 |
预测为类 2 | 2 | 45 | 3 |
预测为类 3 | 0 | 1 | 49 |
此时类 1 的精确率 \(Precision=\frac{43}{43+5+2}=0.86\),召回率 \(Recall=\frac{43}{43+2+0}=0.955556\)。