交叉验证(Cross-Validation)
可能是数据科学家在进行统计分析时最重要的技术之一,因为在实际中经常需要验证一个ML模型的稳定性--模型在新数据集上的泛化能力。它需要确保由数据集得到的ML模型已经获得数据集大部分正确的信息,并且不能包含太多噪声,换句话说,它的偏差和方差是较小的。本文将要介绍交叉验证的相关概念。
交叉验证是一种模型的验证技术用于评估一个统计分析模型在独立数据集上的概括能力。主要用于在使用ML模型进行预测时,准确衡量一个模型在实际数据集上的效果。具体来说就是将整个数据集划分为若干部分,一部分用以训练模型、一部分用以测试最终模型的优劣、一部分验证模型结构和超参数。
交叉验证的目标是确定一个原数据集的子集,去限制ML模型在训练阶段的一些问题,比如模型的过拟合、欠拟合等,同时提供了一种判断标准去衡量模型在独立数据集上的泛化能力。值得注意的是,数据集和测试集必须是独立同分布,不然反而会得到很槽糕的模型。
交叉验证的用途
交叉验证可以有效评估模型的质量
交叉验证可以有效选择在数据集上表现最好的模型
交叉验证可以有效避免过拟合和欠拟合
- 欠拟合(
Underfitting
)
是指模型不能获取数据集的主要信息,在训练集及测试集上的表示都十分糟糕。- 过拟合(
Overfitting
)
是指模型不仅获取了数据集的信息还提取了噪声数据的信息是的模型在训练集有非常好的表现但在测试集上的表现及其糟糕。
所以可以得出一个较为草率的结论:一个最佳的ML模型在训练集和测试集上都有较好的表现。
通常,基于数据的具体划分方式有多种交叉验证方法。
- Train/Test split(Groups=2)
在这种方法中,我们简单的将数据集划分为两个部分:训练集和测试集且在训练集和测试集之前没有交叉重叠的样本,如果训练集和测试集之间出现了交叉重叠的样本,以此训练得到模型是不可靠的,这也是为什么数据集中不能有重复样本的主要原因。在得到最终的模型之前可以使用整个数据集重新训练模型来对模型的超参数进行调整。
但是这种将数据集分为训练集和测试集的方式有一个很大的缺点:
容易导致过拟合,当数据集的划分不是随机进行的,或者划分出的子集只包含了数据集的一部分特征时,因为无法确定哪些数据点会出现在验证集中,过拟合时无可避免的。因此,只有在拥有足够多的数据时,它才是一个不错的选择。
在Python中使用:
xtrain,xtest,ytrain,ytest = sklearn.model_selection.train_test_split()
实现
Args:
data
要进行划分的数据集,支持列表、数据帧、数组、矩阵
test_size
测试集所占比例,默认为0.25
train_size
训练集所占比例
random_state
随机数种子,用于生成重复随机数,保证实验可复现
shuffle
是否在划分数据集之前打乱数据集
- K-Flod(Groups=k)
当没有足够的数据用于训练模型时,划分数据的一部分进行验证会导致得到模型欠拟合,减少训练集,会使模型丧失部分数据集中重要的特征或趋势,这会增加偏差导致的误差。因此,我们需要一种方法来提供样本集训练模型并且留一部分数据集用于验证模型,k折交叉验证(K-Flod)因此被提出。具体来说,先将数据集打乱,然后再将打乱后的数据集均匀分成k份,轮流选择其中的k-1份作为训练集,剩下的一份作验证,计算模型的误差平方和。迭代进行k次后将k次的误差平法和做平均作为选择最优模型的依据。
k折交叉验证在进行k次交叉验证之后,使用k次平均成绩来作为整个模型的得分。每个数据在验证集中出现一次,并且在训练中出现k-1次。这将显著减少欠拟合,因为使用了数据集中的大多数的数据进行训练,同时也降低了过拟合的可能,因为也使用了大多数的数据进行模型的验证。
当我们需要对一些小的数据集进行统计分析时,K-Flod是一个好的选择,在进行k次交叉验证时能获得足够多的模型的质量差异和不同的最佳参数。一般来说,经过长期的经验积累,我们选择或,以产生既不受过高偏差也不受过高偏差影响的测试误差估计。
在Python中使用:
sklearn.model_selection.KFlod()
Args:
n_split
折叠数量,默认为3,至少为2.
shuffle
是否在分割成批次之前打乱数据集,默认不打乱
random_state
随机数种子,在进行打乱数据操作时使用
-
Leave One Out(Groups=len(train))
留一法是K折交叉验证的一个特列,在K折交叉验证中,当K是数据集的样本数时。这意味着,在每次训练中使用k-1个样本作为训练样本,1个样本作为测试集,并遍历数据集中的每个元素。
当我们只有比较少的数据和训练便于重复训练的模型时,这种方法是很有用的。
在Python中使用:
sklearn.model_selection.LeaveOneOut()=KFlod(n_split=n)
Methods:
get_n_splits(X)
返回交叉验证器中的拆分迭代次数,x为训练数据,形状为(n_samples,n_features)
split(x,y,groups)
生成索引已将数据集拆分为训练集和测试集,X为训练集,y为标签,groups为拆分时使用的组标签
- Stratification split
通常,当使用Train/Test split
或KFold的拆分方式时,都会对数据集进行打乱,以得到随机的数据子集。在这种情况下,可以考虑训练集中各类别数据的占比情况,再根据同类数据占比来选择数据组成数据子集,这就是分层法的原理。如下图所示:
数据集有20个样本,分别属于三类,三个类比在总体的占比依次为,现在需要对数据集进行划分,得到10个目标样本作为训练集或验证集,对此可以根据所占比例依次取4,3,3个样本组成训练集或测试集。这种对数据集进行分层提取数据的放法,对于小数据集、不平衡数据集、多分类问题是有很好的效果的,因为它充分考虑了数据内部的分布情况,使得我们所得到的子集(训练集和测试集)继承了数据集的分布特性。
一般来说,对于一个平衡的大数据集,分层法(Stratification split)和对数据集进行随机打乱之后再进行划分的方式得到的结果是相同的。
在什么样的情况下需要使用这些技术呢?
如果拥有足够的数据,并且对于不同的划分方式都能得到类似的模型得分(误差平方和)和最佳模型参数,那么Train/Test split是一个比较好的选择。与之相反,当对于不同的划分我们总是能得到不同的模型得分和最佳模型参数时,KFlod是一个好的选择。而当对小数据集进行处理时,留一法(LeaveOneOut)是更好的选择。分层法能使验证集更加稳定并且对于小而不平衡的数据集是有奇效的。
如何确定KFlod的k值呢?
随着k的增加,偏差会随着误差的增大而减小;而方差会随着误差的增大而增大;计算的成本也会随之增大。显然,随着k的增大,你将需要花费更多的时间和内存去进行计算。随着k的减小,模型的方差会减小,但是模型的偏差将变得更大,所需的计算成本也随之减少。对于一个优良的ML模型,它的方差和偏差应该是相对均衡的,才能兼顾模型的拟合优度和泛化能力。
通常对于大数据集或是建议首选的,而对于小数据集推荐使用留一法。
- Summary
在数据分析中,交叉验证是非常有用的用以评估模型效果的方法,特别是防止过拟合和欠拟合方面。此外,对于模型超参数的确定也是极其有效的,以此选择的参数得到模型会得到更小的测试误差。
本文是翻译Towards Data Science网站的一篇文章,如有错漏,请不吝指正,谢谢。
原文地址:Cross-Validation
原作者主页:Georgios Drakos
关于交叉验证的更多实例可以参考我的另一篇博文:Python机器学习及分析工具:Scikit-learn篇