验证和交叉验证(Validation & Cross Validation)
之前在《训练集,验证集,测试集(以及为什么要使用验证集?)(Training Set, Validation Set, Test Set)》一文中已经提过对模型进行验证(评估)的几种方式。下面来回顾一下什么是模型验证的正确方式,并详细说说交叉验证的方法。
验证(Validation):把数据集随机分成训练集,验证集,测试集(互斥)。用训练集训练出模型,然后用验证集验证模型,根据情况不断调整模型,选出其中最好的模型,记录最好的模型的各项设置,然后据此再用(训练集+验证集)数据训练出一个新模型,作为最终的模型,最后用测试集评估最终的模型。
(注:这是一个完整的模型评估和模型选择过程。如果仅对单个模型进行评估,只需要前面两个步骤:用训练集训练出模型,然后用验证集验证模型。)
需要注意的是:有时我们拿到的数据是按类别排序好的,此时我们千万不能简单地把前n项作为训练集,后m项作为验证集,而是要把数据集重新洗牌,然后再随机抽取(抽取后不放回)。此外,需要尽量使得训练集和验证集的数据分布一致。比如说在分类任务中,训练集和验证集应保持相似的类别比例。这需要通过特定的采样方法来达到这一结果,这种采样方法称为分层采样(Stratified Sampling),简单来说就是如果训练集中有60%的正例,那么验证集中也需要有差不多60%的正例。分层采样也可以和交叉验证结合使用。
有些资料上把验证也算作交叉验证的一种方式,称为留出法(Holdout Validation),但在我的概念中它不应该算作交叉验证,因为数据并没有被交叉使用(既用作训练,又用作验证)。但是多次验证(多次随机划分训练集和验证集)然后取平均值则是一种交叉验证方法,称为蒙特卡洛交叉验证,下面会详细说。
下面来说说什么是交叉验证:
交叉验证(Cross Validation)也是一种模型验证技术。简单来说就是重复使用数据。除去测试集,把剩余数据进行划分,组合成多组不同的训练集和验证集,某次在训练集中出现的样本下次可能成为验证集中的样本,这就是所谓的“交叉”。最后用各次验证误差的平均值作为模型最终的验证误差。
为什么要用交叉验证?
大家知道,之前我们说的留出法(holdout)需要从数据集中抽出一部分作为验证集。如果验证集较大,那么训练集就会变得很小,如果数据集本身就不大的话,显然这样训练出来的模型就不好。如果验证集很小,那么此验证误差就不能很好地反映出泛化误差。此外,在不同的划分方式下,训练出的不同模型的验证误差波动也很大(方差大)。到底以哪次验证误差为准?谁都不知道。但是如果将这些不同划分方式下训练出来的模型的验证过程重复多次,得到的平均误差可能就是对泛化误差的一个很好的近似。
交叉验证的几种方法:
1. 留一法(Leave One Out Cross Validation,LOOCV)
假设数据集一共有m个样本,依次从数据集中选出1个样本作为验证集,其余m-1个样本作为训练集,这样进行m次单独的模型训练和验证,最后将m次验证结果取平均值,作为此模型的验证误差。
(注:这里说的数据集都是指已经把测试集划分出去的数据集,下同)
留一法的优点是结果近似无偏,这是因为几乎所有的样本都用于模型的拟合。缺点是计算量大。假如m=1000,那么就需要训练1000个模型,计算1000次验证误差。因此,当数据集很大时,计算量是巨大的,很耗费时间。除非数据特别少,一般在实际运用中我们不太用留一法。
2. K折交叉验证(K-Fold Cross Validation)
把数据集分成K份,每个子集互不相交且大小相同,依次从K份中选出1份作为验证集,其余K-1份作为训练集,这样进行K次单独的模型训练和验证,最后将K次验证结果取平均值,作为此模型的验证误差。当K=m时,就变为留一法。可见留一法是K折交叉验证的特例。
根据经验,K一般取10。(在各种真实数据集上进行实验发现,10折交叉验证在偏差和方差之间取得了最佳的平衡。)
3. 多次K折交叉验证(Repeated K-Fold Cross Validation)
每次用不同的划分方式划分数据集,每次划分完后的其他步骤和K折交叉验证一样。例如:10 次 10 折交叉验证,即每次进行10次模型训练和验证,这样一共做10次,也就是总共做100次模型训练和验证,最后将结果平均。这样做的目的是让结果更精确一些。(研究发现,重复K折交叉验证可以提高模型评估的精确度,同时保持较小的偏差。)
4. 蒙特卡洛交叉验证(Monte Carlo Cross Validation)
即将留出法(holdout)进行多次。每次将数据集随机划分为训练集和验证集,这样进行多次单独的模型训练和验证,最后将这些验证结果取平均值,作为此模型的验证误差。与单次验证(holdout)相比,这种方法可以更好地衡量模型的性能。与K折交叉验证相比,这种方法能够更好地控制模型训练和验证的次数,以及训练集和验证集的比例。缺点是有些观测值可能从未被选入验证子样本,而有些观测值可能不止一次被选中。(偏差大,方差小)
总结:在数据较少的情况下,使用K折交叉验证来对模型进行评估是一个不错的选择。如果数据特别少,那么可以考虑用留一法。当数据较多时,使用留出法则非常合适。如果我们需要更精确一些的结果,则可以使用蒙特卡洛交叉验证。
此外,需要特别注意的是:如果我们要对数据进行归一化处理或进行特征选择,应该在交叉验证的循环过程中执行这些操作,而不是在划分数据之前就将这些步骤应用到整个数据集。
上面说的是对单个模型进行的交叉验证。如果要在多个不同设置的模型中进行选择,那么步骤和验证类似:首先将数据集划分为训练集和测试集,然后用交叉验证方法划分训练集(划分为训练集和验证集),训练出不同模型后,按验证集误差选出其中最好的模型,记录最好模型的各项设置,然后据此再用(训练集+验证集)数据训练出一个新模型,作为最终的模型,最后用测试集评估最终的模型。
可以看出,在上述模型评估和模型选择过程中,除了对模型进行评估之外,验证和交叉验证还有另外一个作用,就是对超参数进行优化。之前我们所说的根据情况不断调整模型就是其中一种超参数优化方式,叫做试错。另外一种超参数优化方式是:列出各种不同超参数设置的算法;使用验证或交叉验证方法在训练数据上训练出这些不同的模型,然后对这些模型在验证集上的性能进行评估;之后选择其中最好的模型对应的超参数设置。这种超参数优化方式称为网格搜索。当然还有其他的超参数优化方式,请见:超参数优化方法(Hyperparameter Tuning)---试错(Babysitting),网格搜索(Grid Search),随机搜索(Random Search),贝叶斯优化(Bayesian Optimization)。
对于超参数优化,推荐用10折交叉验证。