由于出现类似鸢尾花数据集这种分段数据可能简单的交叉验证无法适用,所以这里引用了分层K折交叉验证。在分层交叉验证中,我们划分数据,使得每个折中类别之间的比例整数与数据集中的比例相同,如下图所示:

mglearn.plots.plot_stratified_cross_validation()




机器学习K折交叉验证代码 k折交叉验证法的步骤_机器学习K折交叉验证代码

当数据按照类别标签排序时,标准交叉验证和分成交叉验证的对比



适用分层交叉验证可以使得具有明显分成的数据集在分成的时候各层数据在各个模型中都存在,适用分成K折交叉验证来验证一个分类器,通常要比交叉验证的效果要好,因为它可以对泛化性能做出更加可靠的评估(使用简单的k折交叉验证是,有可能某个折中只有样本A而无样本B,从而使得该模块的精度预测为0)。

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

对交叉验证的更多控制:我们之前看到,可以利用cv来参数来调节cross_val_score所使用的折数,但scikit-learn允许提供一个交叉验证分类器(cross_validation spliter)作为cv参数,来对数据划分过程做更加精细的控制。对于大多数使用场景而言,回归问题默认的k折交叉验证与分类问题的分层k折交叉验证的表现都很好。但是有些情况却有所不同。

如我们想要在一个分类数据集上使用标准k折交叉验证来重现别人的结果,为了实现这一点,我们首先必须从model_selection模块中导入KFold分类器,并用我们想要使用的折数来将其实例化。

from sklearn.model_selection import KFold
kfold = KFold(n_splits=8)
#我们可以将kfold分类器对象作为cv参数传入cross_val_score
print("Cross val score is :{}".format(cross_val_score(logreg, iris.data, iris.target,
cv=kfold)))

运行结果为:

Cross val score is :
[1. 1. 0.94736842 0.63157895 0.57894737 1.
0.66666667 0.94444444]

通过这种验证,我们可以验证,在iris数据集上,使用3折交叉验证(不分层)确实是一种非常差的主意:

from sklearn.model_selection import KFold
kfold = KFold(n_splits=3)
#我们可以将kfold分类器对象作为cv参数传入cross_val_score
print("Cross val score is :{}".format(cross_val_score(logreg, iris.data, iris.target,
cv=kfold)))

运行结果为:

Cross val score is :

[0. 0. 0.]

因为在iris数据集中,如果分为3折,每一折对应的内容都不同(没有交叉数据),所以学不到任何内容。解决这个问题的另一种方法是将数据打乱来代替分层。当然,如果我们将数据打乱,那么还需要固定random_state来获得可重复的打乱效果;否则每次运行cross_val_score将会得到不同的结果,因为每次都进行了不同的随机划分。在划分前将其打乱可以得到更好的结果,如下代码:

kfold = KFold(n_splits=3, shuffle=True, random_state=0)
print("KFold cross-validation scores:{}".format(cross_val_score(logreg,
iris.data, iris.target, cv=kfold)))
运行后其结果如下:
KFold cross-validation scores:
[0.9 0.96 0.96]

由此可见使用K分层交叉验证后iris数据集即使是使用三折,也能取到很好的学习效果。

留一法交叉验证:另一种常见的交叉验证方法是留一法(leave-one-out)。该方法可以看作是每折只包含单个样本的k折交叉验证,对于每次划分,选择单个数据点作为测试集,这种方法一般非常耗时,特别对于大型数据集来说,但是小型的数据集上优势可以给出更好的预测结果。示例代码如下:

from sklearn.model_selection import LeaveOneOut
leave = LeaveOneOut()
scores = cross_val_score(logreg, iris.data, iris.target, cv=leave)
print("Number of cv iterations: