k折交叉验证过程是估计机器学习算法或配置在数据集上性能的标准方法。
k折交叉验证过程的一次运行可能导致模型性能的估计值有噪声。不同的数据分割可能导致非常不同的结果。
重复k折交叉验证提供了一种改进机器学习模型估计性能的方法。这只需重复交叉验证过程多次,并报告所有运行中的所有折叠的平均结果。预期这个平均结果是使用标准误差计算得出的模型在数据集上真实未知的基础平均性能的更准确估计。
在本教程中,您将了解用于模型评估的重复k折交叉验证。
完成本教程后,您将了解:
- 来自k折交叉验证单次运行的平均性能可能存在噪声。
- 重复k折交叉验证提供了一种减少平均模型性能估计误差的方法。
- 如何在Python中使用重复k折交叉验证评估机器学习模型。
开始您的项目,阅读我的新书《Python机器学习精要》,其中包括分步教程以及所有示例的Python源代码文件。
让我们开始吧。

在Python中使用重复k折交叉验证进行模型评估
照片由lina smith拍摄,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- k折交叉验证
- 重复k折交叉验证
- Python中的重复k折交叉验证
k折交叉验证
通常使用 k 折交叉验证在数据集上评估机器学习模型。
k折交叉验证过程将有限的数据集划分为k个不重叠的折。k个折中的每一个都有机会被用作保留的测试集,而所有其他折叠共同用作训练数据集。总共拟合和评估k个模型在k个保留的测试集上,并报告平均性能。
有关 k 折交叉验证程序的更多信息,请参阅教程
可以使用scikit-learn机器学习库轻松实现k折交叉验证过程。
首先,我们定义一个合成分类数据集,作为本教程的基础。
可以使用make_classification()函数创建合成二分类数据集。我们将配置它生成1000个样本,每个样本有20个输入特征,其中15个有助于目标变量。
以下示例创建并总结了数据集。
1 2 3 4 5 6 |
# 测试分类数据集 from sklearn.datasets import make_classification # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=1) # 汇总数据集 print(X.shape, y.shape) |
运行该示例将创建数据集并确认其包含1000个样本和10个输入变量。
伪随机数生成器的固定种子确保每次生成数据集时都能获得相同的样本。
1 |
(1000, 20) (1000,) |
接下来,我们可以使用k折交叉验证在此数据集上评估模型。
我们将评估逻辑回归模型,并使用KFold类执行交叉验证,配置为打乱数据集并设置k=10,这是一个流行的默认值。
将使用cross_val_score()函数执行评估,该函数接收数据集和交叉验证配置,并返回为每个折计算的分数列表。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 使用k折交叉验证评估逻辑回归模型 from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score 从 sklearn.线性模型 导入 LogisticRegression # 创建数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=1) # 准备交叉验证过程 cv = KFold(n_splits=10, random_state=1, shuffle=True) # 创建模型 model = LogisticRegression() # 评估模型 scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行该示例将创建数据集,然后使用10折交叉验证对其进行逻辑回归模型评估。然后报告数据集上的平均分类准确率。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。可以尝试运行几次示例并比较平均结果。
在这种情况下,我们可以看到模型实现了约86.8%的估计分类准确率。
1 |
准确率:0.868 (0.032) |
现在我们熟悉了k折交叉验证,让我们看看一个重复该过程的扩展。
重复k折交叉验证
通过k折交叉验证对模型性能的估计可能存在噪声。
这意味着每次运行该过程时,都可以实现数据集到k折的不同分割,从而导致性能分数分布不同,从而导致模型性能的平均估计值不同。
从一次k折交叉验证到另一次k折交叉验证的估计性能的差异量取决于所使用的模型和数据集本身。
模型性能的嘈杂估计可能会令人沮丧,因为它可能不清楚使用哪个结果来比较和选择最终模型来解决问题。
减少估计模型性能噪声的一种解决方案是增加k值。这将减少模型估计性能的偏差,尽管它会增加方差:例如,使结果更紧密地与评估中使用的特定数据集相关联。
另一种方法是多次重复k折交叉验证过程,并报告所有折叠和所有重复的平均性能。这种方法通常称为重复k折交叉验证。
…重复k折交叉验证会多次复制该过程。例如,如果重复5次10折交叉验证,将使用50个不同的保留集来估计模型功效。
— 第70页,应用预测建模,2013。
重要的是,k折交叉验证过程的每次重复都必须在分割成不同折的数据集上执行。
重复k折交叉验证的好处是改进了平均模型性能的估计,但代价是拟合和评估更多模型。
重复的常见次数包括3、5和10。例如,如果使用3次10折交叉验证的重复来估计模型性能,则意味着需要拟合和评估(3 * 10)或30个不同的模型。
- 适用:适用于小型数据集和简单模型(例如线性模型)。
因此,该方法适用于中小型数据集和/或拟合和评估计算成本不高的模型。这表明该方法可能适用于线性模型,而不适用于拟合缓慢的模型(如深度学习神经网络)。
与k折交叉验证本身一样,重复k折交叉验证易于并行化,其中每个折或每个重复的交叉验证过程可以在不同的核心或不同的机器上执行。
Python中的重复k折交叉验证
scikit-learn Python机器学习库通过RepeatedKFold类提供了重复k折交叉验证的实现。
主要参数是折的数量(n_splits),即k折交叉验证中的“k”,以及重复的数量(n_repeats)。
k的一个好默认值是k=10。
重复次数的良好默认值取决于数据集上模型性能估计的噪声程度。3、5或10次重复的值可能是一个好的开始。重复次数超过10次可能是不必要的。
1 2 3 |
... # 准备交叉验证过程 cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1) |
下面的示例演示了对我们的测试数据集进行重复k折交叉验证。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 使用重复k折交叉验证评估逻辑回归模型 from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import RepeatedKFold from sklearn.model_selection import cross_val_score 从 sklearn.线性模型 导入 LogisticRegression # 创建数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=1) # 准备交叉验证过程 cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1) # 创建模型 model = LogisticRegression() # 评估模型 scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行该示例将创建数据集,然后使用三次重复的10折交叉验证对其进行逻辑回归模型评估。然后报告数据集上的平均分类准确率。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。可以尝试运行几次示例并比较平均结果。
在这种情况下,我们可以看到模型实现的估计分类准确率约为86.7%,低于先前报告的单次运行结果86.8%。这可能表明单次运行结果可能过于乐观,而三次重复的结果可能更好地估计了模型真实的平均性能。
1 |
准确率:0.867 (0.031) |
重复k折交叉验证的期望是,重复的平均值将比单次k折交叉验证过程的结果更可靠的模型性能估计。
这可能意味着更少的统计噪声。
一种衡量方法是比较不同重复次数下的平均性能分数的分布。
我们可以想象,模型在数据集上存在一个真实未知的平均性能,并且重复的k折交叉验证运行会估计该平均值。我们可以使用一种称为标准误差的统计工具来估计平均性能误差与真实未知的基础平均性能之间的误差。
标准误差可以作为给定样本大小的误差量或误差范围的指示,该误差量可以从样本均值到基础且未知的总体均值。
标准误差可以计算如下:
- 标准误差 = 样本标准差 / sqrt(重复次数)
我们可以使用scipy的sem()函数来计算样本的标准误差。
理想情况下,我们希望选择一个重复次数,该次数既能最小化标准误差,又能稳定平均估计性能,与其他重复次数相比。
下面的示例通过报告10折交叉验证和1到15次重复过程的模型性能来演示这一点。
考虑到大数定律,我们期望更多地重复该过程将导致更准确的平均模型性能估计。尽管如此,试验并非独立,因此基础统计原理变得具有挑战性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# 比较重复k折交叉验证的重复次数 from scipy.stats import sem from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import RepeatedKFold from sklearn.model_selection import cross_val_score from sklearn.linear_model import LogisticRegression from matplotlib import pyplot # 评估具有给定重复次数的模型 def evaluate_model(X, y, repeats): # 准备交叉验证过程 cv = RepeatedKFold(n_splits=10, n_repeats=repeats, random_state=1) # 创建模型 model = LogisticRegression() # 评估模型 scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) 返回 分数 # 创建数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=1) # 要测试的配置 repeats = range(1,16) results = list() for r in repeats: # 使用给定的重复次数进行评估 scores = evaluate_model(X, y, r) # 总结 print('>%d mean=%.4f se=%.3f' % (r, mean(scores), sem(scores))) # 存储 results.append(scores) # 绘制结果图 pyplot.boxplot(results, labels=[str(r) for r in repeats], showmeans=True) pyplot.show() |
运行该示例将报告使用不同重复次数的10折交叉验证的平均和标准误差分类准确率。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。可以尝试运行几次示例并比较平均结果。
在这种情况下,我们可以看到默认的一次重复似乎比其他结果更乐观,准确率约为86.80%,而其他重复次数为86.73%及以下。
我们可以看到平均值似乎稳定在约86.5%。我们可以将其视为模型性能的稳定估计,并因此选择5或6次重复,这些重复似乎首先近似该值。
从标准误差来看,它随着重复次数的增加而减小,并在约9或10次重复时稳定在约0.003的值,尽管5次重复实现了0.005的标准误差,这是单次重复的一半。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
>1 mean=0.8680 se=0.011 >2 mean=0.8675 se=0.008 >3 mean=0.8673 se=0.006 >4 mean=0.8670 se=0.006 >5 mean=0.8658 se=0.005 >6 mean=0.8655 se=0.004 >7 mean=0.8651 se=0.004 >8 mean=0.8651 se=0.004 >9 mean=0.8656 se=0.003 >10 mean=0.8658 se=0.003 >11 mean=0.8655 se=0.003 >12 mean=0.8654 se=0.003 >13 mean=0.8652 se=0.003 >14 mean=0.8651 se=0.003 >15 mean=0.8653 se=0.003 |
创建箱须图以总结每次重复的分数分布。
橙色线表示分布的中位数,绿色三角形表示算术平均值。如果这些符号(值)重合,则表明分布相当对称,平均值可以很好地反映中心趋势。
这可能提供一个额外的启发式方法来为您的测试框架选择合适的重复次数。
考虑到这一点,对于这个选定的测试框架和算法使用五次重复似乎是一个不错的选择。

k折交叉验证重复次数与分类准确率的箱须图
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
教程
API
- sklearn.model_selection.KFold API.
- sklearn.model_selection.RepeatedKFold API.
- sklearn.model_selection.LeaveOneOut API.
- sklearn.model_selection.cross_val_score API.
文章
总结
在本教程中,您了解了用于模型评估的重复k折交叉验证。
具体来说,你学到了:
- 来自k折交叉验证单次运行的平均性能可能存在噪声。
- 重复k折交叉验证提供了一种减少平均模型性能估计误差的方法。
- 如何在Python中使用重复k折交叉验证评估机器学习模型。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
谢谢Jason的精彩介绍,一如既往的清晰和图文并茂。
关于重复k折示例的结果,我想知道选择5次重复是否真的比选择1次或11次有意义。
考虑到一个简单的3西格玛范围,结果似乎没有显著差异。
>1 mean=0.8680 se=0.011 => 0.8680 位于 [0.835, 0.901]
> 5 mean=0.8658 se=0.005 => 0.8658 位于 [0.851, 0.881]
> 11 mean=0.8655 se=0.003 => 0.8655 位于 [0.856, 0.874]
尽管如此,我同意我们必须选择一个不会低估性能方差的重复次数。因此,为了限制计算时间,4或5次重复会比较好。
在此性能评估的特定问题中,偏差似乎不是问题。
谢谢
Jerome
谢谢。
是的,同意。
非常感谢Jason,你是否会准备一个关于曲线估计和非线性回归(带方程)的教程,因为到目前为止你还没有关于这个主题的教程?
感谢您的建议。
嗨,Jason,
感谢K折验证教程。我们能否找到每个折叠中实际使用了多少总数据?在我的情况下,第7个折叠给出了最佳准确率,而平均最终准确率较低。我在想,如果我们能找到与这个特定折叠相关的模型。我们能否为每个折叠保存模型?
是的,本教程将逐步介绍各个折叠,并报告每个折叠中包含哪些行(行索引)。
https://machinelearning.org.cn/k-fold-cross-validation/
你好,Jason。我执行了上面的步骤,使用了我的数据库,并发现重复7次后模型的准确率很好。现在,我该如何拟合这个模型,以便进行预测?请提供指示。谢谢。
直接在所有数据上拟合模型并开始进行预测,例如 model.fit(X, y)
也许这会有帮助。
https://machinelearning.org.cn/train-final-machine-learning-model/
还有这个。
https://machinelearning.org.cn/make-predictions-scikit-learn/
谢谢!我现在明白了。谢谢Jason!
不客气!
你好Jason,谢谢这篇帖子!我有一个问题,希望能得到你的帮助。
对于使用迁移学习和小型数据集(400张图像)且与所使用的imagenet权重非常不同的CNN(EfficientNet),你会推荐哪种评估技术(k折交叉验证或训练/测试分割)?
我最初认为训练/测试分割就足够了,但我看到你说结果通常非常乐观。我也看到这种k折交叉验证,虽然更准确,但更适合简单的模型。
任何方向都将不胜感激!
如果你有资源,重复分层k折交叉验证;如果没有,则使用训练/测试分割。
非常感谢!🙂
不客气。
你好Jason,感谢这篇很棒的博客。我从你那里学到了很多信息。我想问一个关于同时使用train_test_split和kfold交叉验证是否合乎逻辑的问题?
例如,首先,我应用train_test_split并将数据集划分为X_train、X_test和y_train、y_test,然后我将Kfold用于X_train和y_train并获得结果,然后我能否使用相同的模型来预测X_train?这合乎逻辑吗?
不客气。
你可以做任何能让你对结果有信心的事。
实际上,并不太合理。选择其中一种。
亲爱的 Jason,
非常感谢您提供的教程,以及整个网站。信息非常棒,而且您真的在这里帮助人们解决他们的问题,这非常有意义!
在深入研究重复K折交叉验证的主题时,我偶然在维基百科上看到一条评论,这让我看到了这篇文章(https://limo.libis.be/primo-explore/fulldisplay?docid=LIRIAS1655861&context=L&vid=Lirias&search_scope=Lirias&tab=default_tab&lang=en_US&fromSitemap=1)。
文章提出,与常规K折交叉验证相比,重复K折交叉验证并不一定能更好地估计总体中学习器的预期准确率。他们用充分的解释和模型数据来支持他们的假设。
我的问题是:您(作为专家)对此文章的说法有何看法?如果不是重复K折交叉验证,您会建议哪种类型的验证?
不客气。
谢谢分享,我不熟悉这篇文章,抱歉。
Jason,
使用k=25的Kfold CV,您将获得25个数据分割,但您只会执行一次随机分割。使用重复的Kfold k=5和5次重复,您将获得25个数据分割,但这些数据将被随机分割5次。因此,如果您不设置random_state参数,我可以看到这两种策略之间25次分割会有所不同。如果将random_state参数设置为一个整数,两者之间是否真的有区别?
谢谢
杰夫
为了说清楚,如果将random_state参数设置为一个整数,5次重复k=5是否只会给我同样的5个折叠5次?
谢谢
杰夫
不,每次重复的数据都会经过不同的洗牌和分割。
是的。random_state控制数据的分割方式(分割前的数据洗牌)。
固定random_state可以确保我们每次运行代码时都能获得相同的洗牌,从而获得相同的分割。
洗牌使用伪随机数生成器,random_state是种子。
https://machinelearning.org.cn/introduction-to-random-number-generators-for-machine-learning/
我同意Jeff的观点,您应该使用RepeatedCrossValidation,并且random_state不等于任何数字,这样每次重复时,k折都会被随机分割。否则,我认为重复交叉验证没有意义。
如果您在开始时固定了种子,您会在所有重复中获得相同的随机数序列,而不是每次重复都获得相同的序列。请看这里:
https://scikit-learn.cn/stable/modules/generated/sklearn.model_selection.RepeatedKFold.html
嗨,Jason!
非常感谢!您的博客对我非常有帮助!
我想知道是否有方法可以运行重复的分层K折?
谢谢,
Mariana
谢谢!
是的,请看这个
https://scikit-learn.cn/stable/modules/generated/sklearn.model_selection.RepeatedStratifiedKFold.html
谢谢!
澄清了我所有的疑问,并为我提供了实现重复K折CV的扎实实践步骤。
不客气。
嗨,Jason,
感谢您的教程!
我的问题
我看到Kfold()和RepeatedKfold()都有相同的random_state参数…但在Kfold()中我只看到'shuffle'参数,而在RepeatedKfold()中没有……为什么?
我猜想在RepeatedKfold中,我们通过random_state参数的n_repeat参数来实现等同于'shuffle'参数的效果……我说对了吗?
匆忙地说(不深入思考),我怀疑shuffle在实现中是您所建议的。
嗨 Jayson,
您能否推断出Gridsearch CV和RepeatedKFold(我在sklearn中都见过)之间的区别?
谢谢。
附注:我只是ML的新手,我不知道我问的是否愚蠢。
Grid search 用于调整模型超参数。
Repeated k-fold cross-validation 用于评估模型性能。
如果您愿意,可以在grid search中使用repeated k-fold CV。
实际上,在进行了一些阅读后,我认为RepeatedKFold可以用于Gridsearch的cv参数中。
现在我想知道Gridsearchcv和cross_val_score有什么区别?
它们不都是在交叉验证后给我们分数吗?
cross_val_score() 函数将提供使用交叉验证的单个模型/配置的评估。
嗨 Jayson,
在我的第二个评论之后才看到您的回复(由于网络故障)。
那么,RepeatedKFold实际上是否类似于RMSE、MAE等?
因为我在寻找非线性数据的模型性能指标,我的审稿人评论说R2分数对于非线性模型来说不是一个好的分数。就在那时我偶然发现了交叉验证。
所以,我的理解是,当我们在Gridsearch中使用Repeatedkfold时,
GridSearch会采用给定的超参数的一种排列,将其拟合到我们的数据集中,并使用RepeatedKfold检查模型性能。
然后Gridsearch会采用另一种排列,运行它,Repeatedkfold会计算该排列的模型性能。
以此类推……。
最后,从所有Repeatekfold分数中,我们可以确定哪种排列是最好的。
这是正确的吗?
非常感谢您的及时回复。您真的为我们这些初学者付出了努力,这非常值得赞赏。
不,repeatedkfold是一个评估过程,RMSE和MAE是指标。
是的,grid search将使用指定的评估过程(如repeatedkfold)来评估每个配置。“最佳”配置在评估过程中具有最佳的指标分数。
你好,先生,
对于20k的数据点样本,重复K折交叉验证是否合适?
还有一个疑问……您在重复K折CV中设置了random_state=1。但这是否会破坏重复次数的意义?我的意思是,为random_state设置一个值意味着每次运行都会产生相同的结果。
只是一个疑问。如果我错了,请澄清。
不,它确保每次我们在测试环境中评估模型时,它都能获得相同的数据分割。
当然。试试看。
感谢您的回复。我用我的数据集试了一下,发现对于固定的random_state,10折和重复10折CV(最多3次重复)的结果完全相同。
是什么原因导致结果相同?
模型或无噪声数据集有什么问题吗?
干得好!
也许数据和模型非常稳定。
我阅读了这份详细介绍和嵌套交叉验证的介绍。
我们该如何同时使用它们?这样做有任何优势吗?我有一个模糊的想法,我们可以将重复交叉验证放在嵌套交叉验证的内部部分,以获得比单次内部交叉验证运行更高的置信度结果。
是的,您可以这样做。实际上,内部循环应该看到更少的数据,因此使用重复CV可以帮助提高准确性。
嗨,Jason,
我可以问一下,使用这种或类似的管道与分类报告(例如cv)结合使用时,如何获得类别/标签的共识支持?例如,计算5个折叠的平均精度,即交叉验证(cv)=5?
谢谢你。
祝好
嗨 Malik…以下资源可能令人感兴趣。
https://machinelearning.org.cn/training-validation-test-split-and-cross-validation-done-right/
如何对时间序列预测模型使用统计假设检验?哪种更好?
嗨 Hebi…以下资源可能令人感兴趣。
https://machinelearning.org.cn/sarima-for-time-series-forecasting-in-python/
嗨,这个教程太棒了!非常清晰!我有一个关于我自己项目的问题,因为我的算法会根据不同的数据集(K折随机选择训练样本和测试样本)选择不同的“特征”,因此,在某些迭代中会缺少特征,导致无法构建模型。问题是,我们该如何报告这个问题?这是什么意思?
嗨 Hangbin…非常欢迎!以下资源可以为特征选择与随机算法的关系提供更多说明。
https://machinelearning.org.cn/feature-selection-with-optimization/
在我的论文中,“folds” (k) 的德语翻译应该是什么?或者我应该坚持使用英语术语?
提前感谢
嗨 Stefan…您可能需要与您的导师确认。