mcnemar:用于分类器比较的 McNemar 检验

用于配对名义数据的 McNemar 检验

from mlxtend.evaluate import mcnemar

概述

McNemar 检验 [1](有时也称为“组内卡方检验”)是用于配对名义数据的统计检验。在机器学习(或统计)模型的背景下,我们可以使用 McNemar 检验来比较两个模型的预测准确率。McNemar 检验基于两个模型预测结果的 2x2 列联表。

McNemar 检验统计量

在 McNemar 检验中,我们提出零假设,即概率相同,或者简单地说:两个模型中没有任何一个比另一个表现更好。因此,备择假设是两个模型的表现不相等。

McNemar 检验统计量(“卡方”)可以按如下方式计算

如果单元格 c 和 b 的总和足够大,则值遵循具有一个自由度的卡方分布。在设定显著性阈值(例如,)后,我们可以计算 p 值——假设零假设为真,p 值是观察到这个经验卡方值(或更大值)的概率。如果 p 值低于我们选择的显著性水平,我们可以拒绝两个模型表现相等的零假设。

连续性校正

在 Quinn McNemar 发表 McNemar 检验 [1] 大约一年后,Edwards [2] 提出了一个连续性校正版本,这是当今更常用的变体。

精确 p 值

如前所述,对于小样本量 ([3]),建议使用精确二项检验,因为卡方值可能无法很好地通过卡方分布来近似。精确 p 值可以按如下方式计算

其中,以及因子用于计算双侧 p 值。

示例

例如,给定两个模型具有 99.7% 和 99.6% 的准确率,一个 2x2 列联表可以为模型选择提供进一步的见解。

在子图 A 和 B 中,两个模型的预测准确率如下:

  • 模型 1 准确率:9,960 / 10,000 = 99.6%
  • 模型 2 准确率:9,970 / 10,000 = 99.7%

现在,在子图 A 中,我们可以看到模型 2 正确预测了模型 1 预测错误的 11 个样本。反之,模型 1 正确预测了模型 2 预测错误的 1 个样本。因此,基于 11:1 的比例,我们可能会得出结论,模型 2 表现明显优于模型 1。然而,在子图 B 中,比例是 25:15,这对于选择哪个模型更好没有那么明确的结论。

在下面的代码示例中,我们将使用这两个场景 A 和 B 来说明 McNemar 检验。

参考文献

示例 1 - 创建 2x2 列联表

mcnemar 函数期望一个 2x2 列联表作为 NumPy 数组,其格式如下

这样的列联矩阵可以使用 mlxtend.evaluate 中的 mcnemar_table 函数创建。例如

import numpy as np
from mlxtend.evaluate import mcnemar_table

# The correct target (class) labels
y_target = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])

# Class labels predicted by model 1
y_model1 = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0, 0])

# Class labels predicted by model 2
y_model2 = np.array([0, 0, 1, 1, 0, 1, 1, 0, 0, 0])

tb = mcnemar_table(y_target=y_target, 
                   y_model1=y_model1, 
                   y_model2=y_model2)

print(tb)
[[4 1]
 [2 3]]

示例 2 - 场景 B 的 McNemar 检验

现在,让我们继续概述部分中提到的示例,并假设我们已经计算了 2x2 列联表

import numpy as np

tb_b = np.array([[9945, 25],
                 [15, 15]])

为了检验两个模型的预测性能相等的零假设(使用显著性水平为),我们可以进行校正后的 McNemar 检验来计算卡方值和 p 值,如下所示

from mlxtend.evaluate import mcnemar

chi2, p = mcnemar(ary=tb_b, corrected=True)
print('chi-squared:', chi2)
print('p-value:', p)
chi-squared: 2.025
p-value: 0.154728923485

由于 p 值大于我们假定的显著性阈值(),我们无法拒绝零假设,并假设两个预测模型之间没有显著差异。

示例 3 - 场景 A 的 McNemar 检验

与场景 B(示例 2)相反,场景 A 中的样本量相对较小 (b + c = 11 + 1 = 12),小于推荐的 25 [3],无法很好地通过卡方分布近似计算出的卡方值。

在这种情况下,我们需要从二项分布计算精确 p 值

from mlxtend.evaluate import mcnemar
import numpy as np

tb_a = np.array([[9959, 11],
                 [1, 29]])

chi2, p = mcnemar(ary=tb_a, exact=True)

print('chi-squared:', chi2)
print('p-value:', p)
chi-squared: None
p-value: 0.005859375

假设我们也以显著性水平为进行此检验,我们可以拒绝两个模型在该数据集上表现一样好的零假设,因为 p 值()小于.

API

mcnemar(ary, corrected=True, exact=False)

用于配对名义数据的 McNemar 检验

参数

  • ary : array-like, shape=[2, 2]

    2 x 2 列联表(由 evaluate.mcnemar_table 返回),其中 a: ary[0, 0]: 两个模型都正确预测的样本数 b: ary[0, 1]: 模型 1 正确但模型 2 预测错误的样本数 c: ary[1, 0]: 模型 2 正确但模型 1 预测错误的样本数 d: aryCell [1, 1]: 两个模型都预测错误的样本数

  • corrected : array-like, shape=[n_samples] (默认值: True)

    如果为 True,则使用 Edward 的连续性校正计算卡方值

  • exact : bool, (默认值: False)

    如果为 True,则使用精确二项检验,将 b 与参数 n = b + c 且 p = 0.5 的二项分布进行比较。强烈建议在样本量小于 25 时使用 exact=True,因为卡方值无法很好地通过卡方分布来近似!

返回值

  • chi2, p : float 或 None, float

    返回卡方值和 p 值;如果 exact=True(默认值:False),则 chi2None

示例

For usage examples, please see
[https://mlxtend.cn/mlxtend/user_guide/evaluate/mcnemar/](https://mlxtend.cn/mlxtend/user_guide/evaluate/mcnemar/)

Python