使用LOOCV评估机器学习算法

留一法交叉验证(Leave-One-Out Cross-Validation),简称 **LOOCV**,是一种用于估计机器学习算法在对未用于训练模型的数据进行预测时的性能的过程。

这是一个计算量很大的过程,尽管它能提供可靠且无偏的模型性能估计。虽然使用简单且无需配置,但有时不应使用此过程,例如当您拥有非常大的数据集或需要评估计算成本很高的模型时。

在本教程中,您将了解如何使用留一法交叉验证来评估机器学习模型。

完成本教程后,您将了解:

  • 当您拥有小型数据集,或者模型性能的准确估计比方法的计算成本更重要时,留一法交叉验证过程是合适的。
  • 如何使用 scikit-learn 机器学习库执行留一法交叉验证过程。
  • 如何使用留一法交叉验证评估分类和回归的机器学习算法。

开始您的项目,阅读我的新书《Python 机器学习精通》,其中包含分步教程以及所有示例的Python 源代码文件。

让我们开始吧。

LOOCV for Evaluating Machine Learning Algorithms

使用LOOCV评估机器学习算法
照片由 Heather Harvey 拍摄,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. LOOCV 模型评估
  2. Scikit-Learn 中的 LOOCV 过程
  3. LOOCV 评估机器学习模型
    1. LOOCV 用于分类
    2. LOOCV 用于回归

LOOCV 模型评估

交叉验证,或 k 折交叉验证,是一种用于估计机器学习算法在对训练模型期间未使用的数据进行预测时的性能的过程。

交叉验证有一个单一的超参数“k”,它控制数据集被分割成的子集的数量。分割完成后,每个子集都有机会被用作测试集,而所有其他子集组合在一起用作训练数据集。

这意味着 k 折交叉验证涉及拟合和评估 *k* 个模型。这反过来提供了数据集上模型性能的 k 个估计,可以使用均值和标准差等摘要统计数据进行报告。然后可以使用此分数来比较并最终选择用于数据集的“最终模型”的模型和配置。

k 的典型值是 k=3、k=5 和 k=10,其中 10 是最常见的值。这是因为,经过广泛测试,10 折交叉验证在计算成本低和模型性能估计偏差低方面提供了良好的平衡,与其他 k 值和单一的训练-测试分割相比。

有关 k 折交叉验证的更多信息,请参阅教程

留一法交叉验证,或 LOOCV,是 k 折交叉验证的一种配置,其中 *k* 被设置为数据集中示例的数量。

LOOCV 是 k 折交叉验证的一种极端版本,具有最高的计算成本。它需要为训练数据集中每个示例创建一个模型并进行评估。

如此多的拟合和评估模型的优势在于,它提供了更稳健的模型性能估计,因为数据集中的每一行都有机会代表整个测试数据集。

考虑到计算成本,LOOCV 不适用于非常大的数据集,例如超过数十万或数十万个示例的数据集,或者成本高昂的模型(如神经网络)。

  • 不要使用 LOOCV:大型数据集或拟合成本高的模型。

考虑到改进的模型性能估计,LOOCV 适用于模型性能估计至关重要的情况。尤其是在数据集很小(例如少于几千个示例)的情况下,这可能导致模型在训练期间过拟合,并导致模型性能估计存在偏差。

此外,由于未使用训练数据集的抽样,此估计过程是确定性的,与提供随机估计模型性能的训练-测试分割和其他 k 折交叉验证确认不同。

  • 使用 LOOCV:小型数据集或模型性能估计至关重要时。

在通过 LOOCV 评估模型并选择最终模型和配置后,将使用所有可用数据拟合最终模型,并用于对新数据进行预测。

现在我们熟悉了 LOOCV 过程,让我们看看如何在 Python 中使用该方法。

Scikit-Learn 中的 LOOCV 过程

scikit-learn Python 机器学习库通过 LeaveOneOut 类提供了 LOOCV 的实现。

该方法没有配置,因此,在创建类的实例时无需提供参数。

创建后,可以调用 *split()* 函数并提供要枚举的数据集。

每次迭代都会返回可用于提供数据集的训练集和测试集的行索引。

这些索引可用于数据集数组的输入(*X*)和输出(*y*)列来分割数据集。

训练集可用于拟合模型,测试集可用于通过首先进行预测并计算预测值与预期值之间的性能指标来对其进行评估。

可以保存每次评估的分数,并报告最终的平均模型性能估计。

我们可以将它们结合起来,演示如何使用 LOOCV 在使用 make_blobs() 函数创建的合成二元分类数据集上评估 RandomForestClassifier 模型。

完整的示例如下所示。

运行示例手动估算随机森林分类器在合成数据集上的性能。

鉴于数据集有 100 个示例,这意味着创建了 100 个训练/测试分割,数据集中每个单独的行都有机会被用作测试集。同样,创建并评估了 100 个模型。

然后报告了所有预测的分类准确率,在这种情况下为 99%。

手动枚举折的缺点是它很慢,并且涉及大量可能引入错误的代码。

使用 LOOCV 评估模型的替代方法是使用 cross_val_score() 函数

此函数通过“cv”参数接收模型、数据集和实例化的 LOOCV 对象。然后返回一个准确率分数样本,可以通过计算均值和标准差来汇总。

我们还可以将“n_jobs”参数设置为 -1 以使用所有 CPU 核心,从而大大降低拟合和评估如此多模型的计算成本。

下面的示例演示了如何使用 *cross_val_score()* 函数在同一合成数据集上使用 LOOCV 评估 *RandomForestClassifier*。

运行示例自动估算随机森林分类器在合成数据集上的性能。

所有折的平均分类准确率与我们之前的手动估算相符。

现在我们熟悉了如何使用 LeaveOneOut 类,让我们看看如何使用它来评估真实数据集上的机器学习模型。

LOOCV 评估机器学习模型

在本节中,我们将探讨使用 LOOCV 过程在标准分类和回归预测建模数据集上评估机器学习模型。

LOOCV 用于分类

我们将演示如何使用 LOOCV 在声纳数据集上评估随机森林算法。

声纳数据集是一个标准的机器学习数据集,包含 208 行数据,具有 60 个数值输入变量和一个具有两个类别值的目标变量,例如二元分类。

该数据集涉及预测声纳回波是否指示岩石或模拟水雷。

无需下载数据集;我们将在工作示例中自动下载它。

下面的示例下载数据集并汇总其形状。

运行此示例将下载数据集并将其拆分为输入和输出元素。正如预期的那样,我们可以看到有 208 行数据和 60 个输入变量。

现在我们可以使用 LOOCV 评估模型。

首先,加载的数据集必须分为输入和输出部分。

接下来,我们定义 LOOCV 过程。

然后我们可以定义要评估的模型。

然后使用 *cross_val_score()* 函数来枚举折、拟合模型,然后进行预测和评估。然后我们可以报告模型性能的均值和标准差。

将这些结合起来,完整的示例列在下面。

运行示例首先加载数据集并确认输入和输出元素的行数。

注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能有所不同。可以考虑运行示例几次并比较平均结果。

然后使用 LOOCV 评估模型,在对新数据进行预测时的模型性能约为 82.2% 的准确率。

LOOCV 用于回归

我们将演示如何使用 LOOCV 在房价数据集上评估随机森林算法。

住房数据集是一个标准的机器学习数据集,包含 506 行数据,其中有 13 个数值输入变量和一个数值目标变量。

该数据集涉及根据美国波士顿郊区的房屋细节来预测房价。

无需下载数据集;我们将在工作示例中自动下载它。

下面的示例下载并加载数据集为 Pandas DataFrame,并汇总数据集的形状。

运行示例可确认数据集有 506 行和 13 个输入变量以及单个数字目标变量(共 14 个)。

现在我们可以使用 LOOCV 评估模型。

首先,加载的数据集必须分为输入和输出部分。

接下来,我们定义 LOOCV 过程。

然后我们可以定义要评估的模型。

然后使用 *cross_val_score()* 函数来枚举折、拟合模型,然后进行预测和评估。然后我们可以报告模型性能的均值和标准差。

在这种情况下,我们使用适合回归的平均绝对误差(MAE)性能指标。

将这些结合起来,完整的示例列在下面。

运行示例首先加载数据集并确认输入和输出元素的行数。

注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能有所不同。可以考虑运行示例几次并比较平均结果。

模型使用 LOOCV 进行评估,模型在对新数据进行预测时的性能是平均绝对误差约为 2.180(千美元)。

进一步阅读

如果您想深入了解,本节提供了更多关于该主题的资源。

教程

API

总结

在本教程中,您了解了如何使用留一法交叉验证评估机器学习模型。

具体来说,你学到了:

  • 当您拥有小型数据集,或者模型性能的准确估计比方法的计算成本更重要时,留一法交叉验证过程是合适的。
  • 如何使用 scikit-learn 机器学习库执行留一法交叉验证过程。
  • 如何使用留一法交叉验证评估分类和回归的机器学习算法。

你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。

发现 Python 中的快速机器学习!

Master Machine Learning With Python

在几分钟内开发您自己的模型

...只需几行 scikit-learn 代码

在我的新电子书中学习如何操作
精通 Python 机器学习

涵盖自学教程端到端项目,例如
加载数据可视化建模调优等等...

最终将机器学习带入
您自己的项目

跳过学术理论。只看结果。

查看内容

51 条关于“LOOCV 用于评估机器学习算法”的回复

  1. Asad Khan 2020年7月30日凌晨1:38 #

    对于分类,JACKKNIFE(拔靴法)和 LOOCV 是一样的吗?如果两者不同,它们之间的主要区别是什么?

  2. Kingsley Udeh 2020年7月31日早上9:47 #

    嗨,Jason博士,

    是否有可以参考的来源来将 LOOCV 用于时间序列?

    谢谢

  3. Charles Brauer 2020年8月1日凌晨12:13 #

    您写道:

    “模型使用 LOOCV 进行评估,模型在对新数据进行预测时的性能是平均绝对误差约为 2.180(千美元)。”

    您是说“千美元”吗?

    查尔斯

    • Jason Brownlee 2020年8月1日早上6:11 #

      是的,目标定义为:

  4. Jason Brownlee 2020年10月2日早上5:55 #

    谢谢。

  5. madhu krishna 2020年10月7日晚上9:37 #

    您的机器学习博客非常好

  6. Nelson Cárdenas 2020年10月12日晚上11:54 #

    您好,这是一篇很棒的文章和博客。

    我有些疑问。我有一个数据集,分割为训练(60%)、交叉验证(20%)和测试(20%)。我使用交叉验证来估计超参数,我的策略是训练和交叉验证使用 scikit-learn 的分层 4 折交叉验证。这样我就不会在超参数调整中使用测试集。

    我想使用 LOOCV 来评估测试集中的模型,方法如下:

    如果我有 120 个训练示例,40 个交叉验证示例和 40 个测试示例,我想对测试示例中的每个数据进行 LOOCV 40 次,每次只排除一个数据,并使用 199 个示例进行训练。这是某种混合交叉验证。我可以自己实现,但没有 scikitlearn 我会失去并行化。是否有办法让我的策略在 scikitlearn 中奏效?

    提前感谢。

  7. Maria Basic 2020年10月17日凌晨1:20 #

    您好!那么在小型数据集(例如少于 1000 个数据点)的情况下,您建议跳过经典的训练-测试过程(其中交叉验证,在这种情况下是 LOOCV,将在训练子集上执行,然后选择的模型将另外在测试子集上进行测试),而是因为数据集很小而对整个数据集使用 LOOCV 吗?

    • Jason Brownlee 2020年10月17日早上6:09 #

      对于 1000 个数据点,应该使用某种类型的 CV。LOOCV 可能是合适的。

  8. MD MAHMUDUL HASAN 2020年11月3日晚上10:50 #

    您好 Jason,您能否帮我介绍一下如何在 Keras 中为 NN 进行 LOOCV?谢谢。您的网站在我的硕士论文中帮助了我很多。

  9. Taseer Suleman 2020年11月28日晚上11:44 #

    您在存储什么

    y_true.append(y_test[0])
    y_pred.append(yha[0])

    请指导我。这些位置指向什么?

    • Jason Brownlee 2020年11月29日早上8:14 #

      我们将单个预测值和期望值收集到列表中。

  10. Felipe Araya 2021年1月27日晚上11:44 #

    你好,

    一如既往的精彩教程!如果您不介意,我有几个快速问题。

    1. 在使用“cross_val_score”的代码示例中,您是否实际上在使用 LOOCV 而不是典型的 K 折进行嵌套交叉验证?

    2. 在使用“split()”方法的示例中,为什么不使用“train_test_split”创建训练和测试集,然后对训练集应用“split()”方法,这样您就可以在验证集上测试性能,并在测试集上测试模型泛化能力?

    3. 如果您进行两次“split()”,一次是对整个数据,一次是对训练数据,这是否与使用嵌套交叉验证或“cross_val_score”基本相同?

    非常感谢!精彩的教程!

    • Jason Brownlee 2021年1月28日早上5:58 #

      谢谢!

      不,我们正在进行 CV,而不是嵌套 CV。

      我们没有拆分数据集,在本例中我们是手动执行 LOOCV。训练/测试拆分将无法保留 LOOCV 的顺序。

      • Felipe Araya 2021年1月28日上午7:27 #

        嗨,Jason博士,

        但是为什么不进行训练/测试拆分,然后在训练数据上进行 LOOCV 呢?这样基本上会生成一个包含 1 个观测值、n 次的验证集,然后我们可以将这些与测试集进行比较,看看哪个泛化效果最好。我知道这不是你所做的,但这是一种合理的方法吗?

        • Jason Brownlee 2021年1月28日上午8:03 #

          如果您愿意,可以在 LOOCV 中将训练集划分为训练/验证集,以进行超参数调整。

          本教程没有这样做。

  11. Fati 2021年3月5日上午3:05 #

    非常有趣

  12. Ulisses Braga-Neto 2021年4月30日下午12:39 #

    留一法作为分类准确性的估计非常糟糕。它的方差比其他交叉验证估计量高得多(所有估计量都倾向于有变量,但不如留一法)。尤其是在小样本量的情况下,这个问题会很严重。留一法是所有交叉验证估计量中偏差最小的,但方差最大(在小样本情况下,方差更重要)。主要原因是你的测试折叠太小了(只有一个点!)。你最终会从每个折叠中得到一个全有或全无的估计。

  13. Noor 2021年6月1日上午8:38 #

    感谢您的博客,我用我的数据试了一下,但准确率一直显示为 nan?!
    我想这是因为我的数据,我有 8 个输入特征变量和一个数值目标,并且没有空值!

    • Jason Brownlee 2021年6月2日上午5:35 #

      哎呀,也许模型不适用于您的数据。尝试使用您的模型进行一次独立的拟合和预测来调查。

  14. Martin 2021年6月18日上午1:22 #

    我有一个问题。
    我的数据集不是很确定。这意味着,数据并非来自实验,而是来自真实案例,而真实案例的解决方案并不确定。我使用 LOOCV 结合 SVM 和 GBM,我的大约 300 个数据集(超过 1600 个变量)来识别训练集数据中的错误。我消除了(约 10%)的错误分类数据。但现在我不确定我是否最终过度拟合了模型,或者只是选择了“最佳”数据进行训练,并且模型不再适合新数据了?

    • Jason Brownlee 2021年6月18日上午5:44 #

      通常,您应该选择一个能让您对特定数据集上的模型充满信心的评估程序。

      也许 LOOCV 对您来说还不够。

  15. Mohit 2021年8月15日上午12:58 #

    嗨,Jason,

    在 K 折和 LOOCV 之间,我们应该选择哪种交叉验证技术?是否有某些特定场景下我们应该选择一种技术而不是另一种?

    • Adrian Tam
      Adrian Tam 2021年8月17日上午7:17 #

      交叉验证的目的是用未见过的数据来检查你的模型。你是否看到选择一种技术而不是另一种技术的弱点?这当然取决于问题和数据,但我们也可能在选择一种技术时考虑速度、内存占用和其他实际指标。

  16. Andriy 2021年9月21日上午12:40 #

    您在“LOOCV for Regression”中的代码不起作用,并给出了错误消息

    UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 18-23: ordinal not in range(128)

    • Adrian Tam
      Adrian Tam 2021年9月21日上午9:30 #

      尝试在 read_csv() 函数中添加 encoding=”utf-8”。

  17. John 2021年11月23日上午6:58 #

    嗨,Jason,

    关于 loocv 的一个快速问题:测试准确率是否必然等于平均训练准确率(即,n 个模型的平均准确率)?换句话说,训练和测试准确率是否会随着 loocv 收敛?

    谢谢!

    • Adrian Tam
      Adrian Tam 2021年11月23日下午1:39 #

      不。如果您看到测试比训练差很多,那么您就遇到了过拟合问题。我们期望一个好的模型应该具有大致相同的测试和训练准确率。

  18. Markus 2022年2月12日上午1:17 #

    嗨,Jason,

    我有一个关于模型创建的问题。模型是在 cross_val_score 函数中训练的吗?我如何访问该模型,例如,将其转储或读取系数等?

    谢谢!

    • James Carmichael 2022年2月12日下午12:49 #

      Markus,在这种情况下,模型是在 cross_val_score 中训练和评估的。您需要创建一个模型类对象才能捕获模型详细信息。

  19. Markus 2022年2月14日下午6:30 #

    嗨 James,

    我明白了。谢谢!这澄清了很多问题,我只是不明白为什么没有内置函数来获取这个模型……有什么线索可以找到关于如何创建这样的类的想法吗?

    • Markus 2022年2月14日下午7:18 #

      嗨 James,

      不用担心,我刚找到了一些关于这方面的信息和关于 loocv 的更多理论背景。

      谢谢!

  20. Nicola 2022年3月10日上午9:12 #

    嗨 James,

    快速问题,在嵌套的 CV 中使用 LOO 作为外层循环,同时仍为参数优化(内层循环)使用 k-fold,这有意义吗?在使用 LOO 的嵌套 CV 中,是否有更好的策略?

    非常感谢
    Nicola

    • James Carmichael 2022年3月10日上午10:19 #

      你好 Nicola…是的,这是一个合理的策略。试着去实现,然后告诉我们你的发现。

      • Nicola 2022年3月11日上午5:01 #

        太好了,谢谢!

  21. Jeetech Academy 2022年3月14日下午3:16 #

    每一次更新都令人兴奋。但这次尤其令人兴奋!

  22. Ahmad Syukri 2022年6月23日下午7:10 #

    但对于(多)线性回归来说,LOOCV 的计算成本非常低?它有一个封闭形式的解。

  23. Miguel Senra 2022年8月25日下午11:14 #

    你好 James,你还好吗?我有一些疑问

    LOOCV 和其他任何类型的 CV 是否都会为我的模型提供未见数据的预测区间?还是只有其中一个?我的意思是,我是否可以认为任何新的预测都应该在 LOOCV 找到的 +mae 和 -mae 之间(当然是在预测值周围)。

    另外,当我的模型具有比训练分数好得多的 LOOCV 分数时,这可能意味着什么?

    我的意思是,我将训练数据的预测值与其实际值进行比较,结果比 LOOCV 差?

    我明白当我的训练分数比 LOOCV 或任何其他 CV 技术好得多时,这是一种过拟合情况,但反之呢?

    谢谢!

  24. Simon 2022年10月21日上午6:30 #

    问候,Jason,非常有趣且有帮助的文章。

    按照您的示例,我使用了“scores = cross_val_score(model, X, y, scoring=’neg_mean_absolute_error’, cv=cv, n_jobs=-1)”(使用不同的数据集),但感到困惑的是,两种不同的评分方法给了我相同的结果。

    我的模型是线性回归,我尝试的两种评分方法是“neg_mean_absolute_error”和“neg_root_mean_squared_error”,并且在我所有的 35 个结果中,这两种方法都得到了相同的分数,分数从 0.178 到 2.28,所以这不仅仅是巧合,这些分数是相同的。

    我做错了什么吗?或者在这种模型和验证系统中是否可以预期?

  25. Haj 2023年7月26日下午6:24 #

    嗨,Jason,

    谢谢!很有帮助。我有一个问题想请您帮我核实一下我的理解。cross_val_score 函数实际上并没有拟合模型,对吗?所以我们传递的第一个参数,我们不能肯定地将其作为最终模型/分类器用于后续使用。话虽如此,我在尝试使用它时一直收到“模型尚未拟合”的错误,这是在遵循您的教程之后。这是否意味着我必须对所有 X 和 Y 进行 cross_val_score,然后,要拟合模型,我将其拆分为训练和测试(假设为 70% / 30%),拟合模型,然后将其用于未见过的(测试)数据?我难以捕获最终模型/分类器以便以后与其他数据一起使用,而不会最终得到 N 个分类器(N 是数据点的数量)。等待您的回复,非常感谢!

Leave a Reply

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。