关于k-fold交叉验证的介绍
交叉验证是一种用于评估机器学习模型技能的统计方法。
在应用机器学习中,通常用于比较和选择给定预测建模问题的模型,因为它易于理解、易于实现,并且得到的技能评估的结果通常比其他方法具有更低的偏差。
在本教程中,你将发现对评估机器学习模型技能的k-fold交叉验证过程有一个简单的介绍。
完成本教程后,你将了解:
- k-fold交叉验证是用于估计模型在新数据上的技巧的过程。
- 你可以使用一些常见策略来选择数据集的k值。
- 交叉验证有一些常用的变体,例如在scikit-learn中提供的分层和重复。
我们开始吧。
教程概述
本教程分为5个部分;它们是:
- k-fold交叉验证。
- 配置k。
- 工作示例。
- 交叉验证接口。
- 交叉验证的变化。
k-fold交叉验证
交叉验证是一种重采样过程,用于在有限的数据样本上评估机器学习模型。
该过程只有一个名为k的参数,它指的是给定数据样本要拆分到的组数。因此,该过程通常被称为k-fold交叉验证。当选择了k的特定值时,它可以用来代替模型引用中的k,例如k=10成为10倍交叉验证。
交叉验证主要用于应用机器学习,以评估机器学习模型在不可见数据上的技能。也就是说,使用有限的样本来估计模型在用于对在模型的训练期间未使用的数据进行预测时的总体预期表现。
这是一种流行的方法,因为它易于理解,而且与其他方法(如简单的训练/测试分离)相比,它通常会导致对模型技能的较少偏见或较不乐观的估计。
一般流程如下:
- 随机洗牌数据集。
- 将数据集分割为k个组。
- 对于每个唯一组:
- 将该组作为保持或测试数据集。
- 将剩余的组作为训练数据集。
- 在训练集上拟合一个模型,并在测试集中对其进行评估。
- 保留评估分数并丢弃模型。
- 用模型评价分数样本总结模型技能。
重要的是,数据样本中的每个观察值都被分配到一个单独的组中,并在整个过程中一直留在该组中。这意味着每个样本都有机会在保持组中使用1次,并用于训练模型k-1次。
同样重要的是,在拟合模型之前的任何数据准备都发生在循环内CV分配的训练数据集上,而不是在更广泛的数据集上。这也适用于超参数的任何调整。在循环内执行这些操作失败可能会导致数据泄漏和对模型技能的乐观估计。
k-fold交叉验证运行的结果通常用模型技能得分的平均值进行总结。包括技能分数方差的度量(例如标准偏差或标准误差)也是一种很好的做法。
配置k
必须为你的数据样本仔细选择k值。
对于k的选择错误的值可能导致对模型技能的不具代表性,诸如具有高方差的分数(其可能基于用于拟合模型的数据改变很大),或者高偏差(诸如对模型技能的高估)。
选择k值的三种常见策略如下:
- 代表性:选择k的值使得每个数据样本的训练/测试组足够大以在统计上代表更广泛的数据集。
- k=10:k的值固定为10,通过实验发现,该值通常会导致模型技能估计具有较低的偏差和适度的方差。
- k=n:k的值固定为n,其中n是数据集的大小,以使每个测试样本有机会在坚持数据集中使用。这种方法称为留一交叉验证。
k=10的值在应用机器学习领域非常常见,如果你正在努力为数据集选择一个值,建议使用k=10。
如果为k选择的值不会平均分割数据样本,则一个组将包含示例的其余部分。较佳的选择是将数据样本分成具有相同样本数量的k个组,使得模型技能得分的样本都是相等的。
工作示例
为了使交叉验证过程具体化,让我们看一个工作示例。
假设我们有一个包含6个观测值的数据样本:
[0.1, 0.2, 0.3, 0.4, 0.5, 0.6]
第一步是选择k的值,以确定用于拆分数据的折叠数。在这里,我们将使用k=3的值。这意味着我们将混洗数据,然后将数据分成3组。因为我们有6个观测值,所以每组将有相等数量的2个观测值。
例如:
Fold1: [0.5, 0.2] Fold2: [0.1, 0.3] Fold3: [0.4, 0.6]
然后我们可以利用样本,比如评估机器学习算法的技能。
对三个模型进行训练和评估,每个折叠都有机会成为保持测试集。
例如:
- 模型1:在Fold1+Fold2上进行训练,在Fold3上测试。
- 模型2:在Fold2+Fold3上进行训练,在Fold1上测试。
- 模型3:在Fold1+Fold3上训练,在Fold2上测试。
然后,这些模型在经过评估后被丢弃,因为它们已经达到了它们的目的。
收集每个模型的技能分数并汇总以供使用。
交叉验证接口
我们不需要手动实现k-fold交叉验证。scikit-learn 库提供了一个将拆分给定数据样本的实现。
可以使用scikit-learn的KFold()类。它将分割次数、是否对样本进行混洗以及在混洗之前使用的伪随机数生成器的种子作为参数。
例如,我们可以创建一个实例,该实例将一个数据集拆分成3个文件夹,在拆分之前进行洗牌,并使用值1作为伪随机数生成器。
kfold = KFold(3, True, 1)
然后,可以在将数据样本作为参数提供的类上调用split()函数。重复调用,拆分将返回每组训练和测试集。具体地说,返回的数组包含观察的原始数据样本的索引,用于每次迭代的训练和测试集。
例如,我们可以使用创建的KFold实例枚举数据样本的索引拆分,如下所示:
# enumerate splits for train, test in kfold.split(data): print('train: %s, test: %s' % (train, test))
我们可以将所有这些与上一节的工作示例中使用的小数据集联系在一起。
# scikit-learn k-fold cross-validation from numpy import array from sklearn.model_selection import KFold # data sample data = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6]) # prepare cross validation kfold = KFold(3, True, 1) # enumerate splits for train, test in kfold.split(data): print('train: %s, test: %s' % (data[train], data[test]))
运行该示例将打印为每个训练和测试集选择的特定观察结果。索引直接用于原始数据数组以检索观测值。
train: [0.1 0.4 0.5 0.6], test: [0.2 0.3] train: [0.2 0.3 0.4 0.6], test: [0.1 0.5] train: [0.1 0.2 0.3 0.5], test: [0.4 0.6]
有用的是,scikit-learn中的k倍交叉验证实现是作为更广泛方法中的组件操作提供的,例如网格搜索模型超参数和对数据集上的模型进行评分。
不过,可以直接使用KFold类在建模之前拆分数据集,以便所有模型都使用相同的数据拆分。如果你正在处理非常大的数据样本,这将特别有用。跨算法使用相同的拆分对于你稍后可能希望对数据执行的统计测试有好处。
交叉验证的变化
在k-fold交叉验证过程中有许多变化。
以下是常用的变化:
- 训练/测试拆分:在一个极端情况下,可以将k设置为2(而不是1),以便创建单个训练/测试拆分来评估模型。
- LOOCV:走到另一个极端,可以将k设置为数据集中的观测总数,以便给予每个观测被保持在数据集中的机会。这称为留一交叉验证,简称LOOCV。
- 分层:将数据分成文件夹可能受到一些标准的控制,例如确保每个文件夹具有相同比例的观测值和给定的类型值,例如类结果值。这称为分层交叉验证。
- 重复:这是k-fold交叉验证过程重复n次的地方,其中重要的是,数据样本在每次重复之前被打乱,这导致样本的不同分裂。
scikit-learn库提供了一套交叉验证实现。你可以在Model Selection API中查看完整列表。
进一步阅读
如果你想深入了解,本节提供了更多关于该主题的资源。