5折交叉验证_机器学习理论大会战——模型交叉验证

1 模型评估简述

作为一个监督型学习算法,我们对它所训练出来的学习模型通常都会做一个模型评估与参数寻优工作,以评价所训练出来的学习模型的优劣程度。同时,有效的参数寻优能够为当前构建的学习模型提供最佳的参数取值组合,从而提升模型的预测效率。

对于非监督学习算法,我们前面就曾介绍过,很难对它们开展一个定量的评估工作,因为它们并不清楚最终要学习到的知识是什么,进而也就缺乏评价的基础。最实际的评估办法就是人工评估,比如“专家组”的参考意见等。

在监督型学习算法训练中,我们经常要把一个数据集划分为训练集和测试集,所使用的函数也是我们已经多次打交道的train_test_split()函数。有关这个函数本身的介绍,我们这里不再啰嗦。只简单说说这个函数对开展模型训练有些什么影响。

train_test_split()函数,对数据集的划分是随机的,通常默认情况下,我们会利用该函数把数据划分为两份:75%的数据集作为训练集,剩余25%作为测试集用。但这种划分方式有时也会显得比较失败,原因就在于这种“随机”划分,我们无法控制,不知道最终被随机划分出来的训练集和测试集会是一种怎样的数据分布。可能有时能得到比较幸运的划分结果:所有难以分类的样例都在训练集中。在这种情况下,测试集将仅包含“容易分类的”样例,并且测试集精度会高得不切实际。相反,如果我们“不够幸运”,则可能随机地将所有难以分类的样例都放在测试集中,因此得到一个不切实际的低分数。

在这种情况下,我们就需要考虑其他更加有效的数据集划分方式。这就是我们这里要介绍所谓的“交叉验证”以及“k折交叉验证”等技术的原因所在。

而我们的模型评估,在分类问题上,通常是用模型的score()函数来得出整体的评估值;在回归问题上,则是用R2值来作为模型的评估指标。这点我们在此前的学习算法介绍中不止一次提到过。这里我们不再提。

现在我们来提另一种评估模型的方法——k折交叉验证。所谓的折就是等份的意思,一折就是一等份。k折就是说把数据集等分成k等份。因此,每一等份就叫做一折。k折交叉验证的意思就是,我们先利用第1折作为测试集,剩余的2到k折作为训练集,来训练出一个测试模型,得出该模型的预测精度值;然后我们利用第2折作为测试集,其余部分作为训练集,来训练出一个学习模型,得出该模型的预测精度;以此类推,直到我们选用第k折作为测试集,第1折到第k-1折为训练集,以此来训练出一个学习模型,并得出它的预测精度值。

这样我们就获得了k个学习模型,也得到了k个预测精度值,然后取其平均值就是k折交叉验证下的最终预测精度值,也可以作为模型的最终预测精度值来看待。

这是最基础的k折交叉验证。在Scikit-learn库中,实现基础k折交叉验证的函数由:cross_val_score()来实现,默认情况下的折数为3折。可以通过参数cv的设置来改变折数。

此外,我们还有其他的k折交叉验证机制,是源自于对基础k折交叉验证机制的改变,比如:

1、分层k折交叉验证机制,Scikit-learn库中的实现函数为:KFold()、StratifiedKFold()。

这种分层k折交叉验证机制,通常用于什么场合呢?我们看一个实际的例子:

假设我们现在获得的数据大致分为5类,且不凑巧的是,这批数据刚好分布得还挺有规律:前五分之一为1类,下一个五分之一为2类,...,最后一个五分之一为5类。如果我们选用基础的cross_val_score()来帮我们做5折交叉验证机制,也就是cv=5,那么我们会发现:第1折只有类别1,第2折只有类别2,第3折只有类别3,第4折只有类别4,第5折只有类别5。因此再做5折交叉验证机制时,我们就会很难受,因为当我们选用第1折作为测试集,其余为训练集时,发现训练过程中缺少了对第1类数据的学习,从而在测试集上展开预测时就会得到0的预测精度值(毕竟没学习过嘛)。以此类推,不论是哪一折作为测试集,所得到的预测精度值一定都是0。

这说明,基础的k折交叉验证机制就失效了,需要我们改变一下思路。打乱这批数据,并采用分层k折交叉验证机制:在分层交叉验证中,我们划分数据,使每个折中类别之间的比例与整个数据集中的比例相同

使用分层k折交叉验证而不是k折交叉验证来评估一个分类器,这通常是一个好主意,因为它可以对泛化性能做出更可靠的估计。在只有10%的样本属于类别B的情况下,如果使用标准k折交叉验证,很可能某个折中只包含类别A的样本。利用这个折作为测试集的话,无法给出分类器整体性能的信息。

对于回归问题,scikit-learn默认使用标准k折交叉验证。也可以尝试让每个折表示回归目标的不同取值,但这并不是一种常用的策略,也会让大多数用户感到意外。

2、留一法验证机制,Scikit-learn库中的实现函数为:LeaveOneOut()。

你可以将留一法交叉验证看作是每折只包含单个样本的k折交叉验证。对于每次划分,你选择单个数据点作为测试集。这种方法可能非常耗时,特别是对于大型数据集来说,但在小型数据集上有时可以给出更好的估计结果。

3、打乱划分交叉验证机制,Scikit-learn库中的实现函数为:ShuffleSplit()。

在打乱划分交叉验证中,每次划分为训练集取样train_size个点,为测试集取样test_size个(不相交的)点。将这一划分方法重复n_iter次。这里的train_size、test_size、n_iter均为ShuffleSplit()函数中的参数,分别表示训练集数据占比,测试集数据占比、打乱数据集并分割数据集的次数。

打乱划分交叉验证可以在训练集和测试集大小之外独立控制迭代次数,这有时是很有帮助的。它还允许在每次迭代中仅使用部分数据,这可以通过设置train_size与test_size之和不等于1来实现。用这种方法对数据进行二次采样可能对大型数据上的试验很有用。ShuffleSplit还有一种分层的形式,其名称为StratifiedShuffleSplit,它可以为分类任务提供更可靠的结果。

4、分组交叉验证,在Scikit-learn库中的实现函数为:GroupKFold(),使用groups组数为参数。

假如我们有这样一批数据,每个类别的数据可能出现多个。如果这时我们采用分层交叉验证机制来度量分类器的性能,那么同一个类别的数据就有可能在训练集与测试集上都出现。此时我们会发现在测试集上预测一个数据的类别会更加轻松,但如果换成一个新的数据,则有可能就没那么预测准确。因此,在这种情况下,我们需要确保训练集与测试包含不同类别的数据。这点与分层k折交叉验证机制有所不同,注意不要搞混淆了。

实现分组交叉验证机制时,最重要的是需要指定这些数据所属的组别,也就是设置好groups。在小批量的数据集上做分组交叉验证机制实现,是相对容易的,因为数据量较小,设置groups来比较容易;可如果数据集规模很大,则此时来设置每个数据样本的group就显得困难得多了。这点需要加以注意。

最后,scikit-learn中还有很多交叉验证的划分策略,适用于更多的使用场景。但标准的KFold、StratifiedKFold和GroupKFold是目前最常用的几种。

下面我们就一一来体验下不同的交叉验证机制下对度量分类器的表现有何不同。

2 交叉验证机制实践

在讨论这些交叉验证机制的实践示例之前,有必要明确一点的是:

不论是分层交叉验证机制、留一法验证机制、打乱划分交叉验证机制还是分组交叉验证机制,其实都是在创建一个“交叉验证分离器”对象。我们在cross_val_score()中有一个cv参数,它可以设置具体的折数。但同时还可以作为一个接纳交叉验证分离器的载体。

因此,我们在常用到的机器学习算法的交叉验证机制方法中,通常都是以cross_val_score()函数为载体,以某个具体的交叉验证机制方法所创造的交叉验证分离器为载体赋予给cv参数,从而实现在当前的交叉验证机制下的分类器性能度量。

比如我们采用分层交叉验证机制,那么就应该按照如下的套路来展开分类器性能度量:

from sklearn.model_selection import KFold

kfold = KFold(n_splits=3, shuffle=True, random_state=0)

print("Cross-validation scores:\n{}".format(

 cross_val_score(logreg, iris.data, iris.target, cv=kfold)))

或者:

from sklearn.model_selection import StratifiedKFold

skf = StratifiedKFold(n_splits=5)

print("Cross-validation scores:\n{}".format(

 cross_val_score(logreg, iris.data, iris.target, cv=skf)))

具备这个基础,我们接下来看两个具体的实践示例。

1、汇总基础k折交叉验证机制、分层k折交叉验证机制、留一法验证机制、打乱划分交叉验证机制的实践示例:

from sklearn.model_selection import cross_val_score

from sklearn.datasets import load_iris

from sklearn.linear_model import LogisticRegression

from sklearn.model_selection import KFold

from sklearn.model_selection import LeaveOneOut

from sklearn.model_selection import StratifiedKFold

from sklearn.model_selection import ShuffleSplit

iris = load_iris()

print("鸢尾花类别:\n{}".format(iris.target))

clf_LR = LogisticRegression()

scores = cross_val_score(clf_LR, iris.data, iris.target)

print("基础k折交叉验证机制的预测精度值: {}".format(scores))

scores = cross_val_score(clf_LR, iris.data, iris.target, cv=5)

print("基础k折交叉验证机制的平均预测精度值e: {:.2f}".format(scores.mean()))

#不打乱数据集,但对数据集划分为5折时的分层交叉验证机制

kf = KFold(n_splits=5)

scores = cross_val_score(clf_LR, iris.data, iris.target, cv=kf)

print("5折的KFold交叉验证机制的预测精度值:{:.2f}".format(scores.mean()))

#打乱数据集后再来开展分层交叉验证机制

kf_3 = KFold(n_splits=3, shuffle=True, random_state=0)

scores = cross_val_score(clf_LR, iris.data, iris.target, cv=kf_3)

print("3折且打乱数据的KFold交叉验证机制的预测精度值:{:.2f}".format(scores.mean()))

#采用StratifiedKFold来开展分层k折交叉验证机制

skf = StratifiedKFold(n_splits=5)

scores = cross_val_score(clf_LR, iris.data, iris.target, cv=skf)

print("5折的StratifiedKFold交叉验证机制的预测精度值:{:.2f}".format(scores.mean()))

#留一法验证机制的表现

loo = LeaveOneOut()

scores = cross_val_score(clf_LR, iris.data, iris.target, cv=loo)

print("留一法验证机制下的平均预测精度值: {:.2f}".format(scores.mean()))

#打乱划分交叉验证机制的表现:

shuffle_split = ShuffleSplit(test_size=.5, train_size=.5, n_splits=10)

scores = cross_val_score(clf_LR, iris.data, iris.target, cv=shuffle_split)

print("打乱划分交叉验证机制的预测精度值:{:.2f}".format(scores.mean()))

其运行结果如下:

鸢尾花类别:

[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2

 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

 2 2]

基础k折交叉验证机制的预测精度值: [0.96078431 0.92156863 0.95833333]

基础k折交叉验证机制的平均预测精度值e: 0.96

5折的KFold交叉验证机制的预测精度值:0.75

3折且打乱数据的KFold交叉验证机制的预测精度值:0.94

5折的StratifiedKFold交叉验证机制的预测精度值:0.96

留一法验证机制下的平均预测精度值: 0.95

打乱划分交叉验证机制的预测精度值:0.92

大家可以从这个运行结果上看出点啥规律吗?比如我们是否可以在鸢尾花数据集上直接就用3折的分层交叉验证机制?另外,不同的交叉验证机制,在同一批数据集上,开展基于同一个学习算法的模型训练,所度量的模型性能的分值也是不一样的,这一点为我们今后实际开展机器学习模型的交叉验证提供了一个很好的参考。

2、我们再看一下有关分组交叉验证机制的一个简单实例:

from sklearn.model_selection import GroupKFold

from sklearn.datasets import make_blobs

from sklearn.model_selection import cross_val_score

from sklearn.linear_model import LogisticRegression

clf_LR = LogisticRegression()

# 创建模拟数据集

X, y = make_blobs(n_samples=12, random_state=0)

# 假设前3个样本属于同一组,接下来的4个属于同一组,以此类推

groups = [0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3]

scores = cross_val_score(clf_LR, X, y, groups, cv=GroupKFold(n_splits=3))

print("分组交叉验证机制的预测精度值:\n{}".format(scores))

其运行结果如下:

分组交叉验证机制的预测精度值:

[0.75       0.8        0.66666667]

3 总结

这一节主要为大家展示了几种常见的交叉验证机制,它们在度量分类器的表现中通常都会起到不错的效果。

虽然介绍的交叉验证机制比较多,但通常我们只需要重点关注一下最常用到的几种即可:KFold、StratifiedKFold和GroupKFold以及最基础的那个cross_val_score验证机制。

OK,本节的知识就为大家分享到这里,谢谢大家。下一节我们将继续分享有关模型的参数寻优方法知识。

5折交叉验证_机器学习理论大会战——模型交叉验证_第1张图片

你可能感兴趣的:(5折交叉验证,k折交叉验证,k折交叉验证法)