Mythsman


乐极生悲,苦尽甘来。


机器学习中的交叉验证思想

简述

在使用训练集对参数进行训练的时候,经常会发现人们通常会将一整个训练集分为三个部分(比如mnist手写训练集)。一般分为:训练集(train_set)评估集(valid_set)测试集(test_set)这三个部分。这其实是为了保证训练效果而特意设置的。其中测试集很好理解,其实就是完全不参与训练的数据,仅仅用来观测测试效果的数据。而训练集评估集则牵涉到下面的知识了。

因为在实际的训练中,训练的结果对于训练集的拟合程度通常还是挺好的(初试条件敏感),但是对于训练集之外的数据的拟合程度通常就不那么令人满意了。因此我们通常并不会把所有的数据集都拿来训练,而是分出一部分来(这一部分不参加训练)对训练集生成的参数进行测试,相对客观的判断这些参数对训练集之外的数据的符合程度。这种思想就称为交叉验证(Cross Validation)。

通常我们使用的交叉验证方法有下面几种:

简单交叉验证(simple cross validation)

简单交叉验证当然很简单了,就是把整个训练集随机分为两部分(通常是70%的训练集,30%的评估集)。

1、首先我们用训练集建立模型,这时候我们需要尝试多种的参数来得到一些不同的模型;

2、对于每一个模型,调用评估集来进行测试,计算出训练误差(通常是以类似损失函数的形式);

3、取训练误差最小的那个模型作为最后的结果;

这个方法当然会存在一些训练数据的浪费,毕竟有大量的数据没有参与真正的训练而是仅仅作为评估。所以这个方法只能在数据非常易得的情况下使用,如果数据比较珍贵,显然这种方法就不适用了。

有时候这个方法好像也被称为HoldOut验证(Hold-Out Method)。其实这也不算是交叉验证了,因为他的训练集并没有交叉。

通常情况下我们是直接选取前70%为训练集,但是如果训练数据是按照一定规律排放的,那么选取数据的时候就要先打乱顺序,或者按照一定的随机方法选取数据。否则训练集就不一定具有一般性了。

K-折交叉验证(S-fold Cross Validation)

这个据说是最常用的验证方法了,步骤如下:

1、将数据集均分为K份

2、从K份中取一份作为评估集,另外K-1份作为训练集,生成K个模型以及这K个模型对于评估集的训练误差;

3、取训练误差最小的那个模型作为最后的结果;

经大量实验验证,据说我们取K=10的时候效果最好。

这个方法一方面保证了数据充分被使用训练了,避免了数据的浪费;另一方面也互相进行了验证,达到了交叉验证的效果,不过计算代价还是有点高。

留p交叉验证(Leave-p-out Cross Validation)

从名字大概就可以看出来了,所谓留p,就是每一次训练都会留下p个数据作为评估集,剩下的n-p个数据作为训练集,分别进行建模测试,取出效果最好的模型。这里我们会发现这p个数据可以有$C_n^p$组可能,所以计算的复杂度还是挺高的。

当然,有时候我们会取p=1,这导致了每一个数据都会独立作为测试集。这种方法又被叫做留一交叉验证(Leave-One-Out Cross Validation),当数据极为匮乏的时候才会使用。

事实上,交叉验证的方法不仅能够提高数据的利用率,更重要的是他也能够在一定程度上解决过拟合(Overfitting)问题,因为过拟合只能很好的拟合训练集中的数据而并不能拟合评估集中的数据。