paired_ttest_kfold_cv: K 折交叉验证配对 t 检验

用于比较两个模型性能的 K 折配对 t 检验程序

from mlxtend.evaluate import paired_ttest_kfold_cv

概述

K 折交叉验证配对 t 检验程序是比较两个模型(分类器或回归器)性能的常用方法,并解决了一些重采样 t 检验程序的缺点;然而,此方法仍然存在训练集重叠的问题,不建议在实践中使用 [1],应改用诸如 paired_ttest_5x2cv 等技术。

为了解释此方法的工作原理,让我们考虑两个估计器(例如分类器)A 和 B。此外,我们还有一个带标签的数据集 D。在常用的留出法中,我们通常将数据集分成两部分:训练集和测试集。在 K 折交叉验证配对 t 检验程序中,我们将测试集分成 k 个大小相等的部分,然后将这些部分中的每一个用于测试,而剩余的 k-1 个部分(组合在一起)用于训练分类器或回归器(即标准的 K 折交叉验证程序)。

在每次 K 折交叉验证迭代中,我们计算 A 和 B 在每个折叠中的性能差异,从而获得 k 个差异测量值。现在,通过假设这 k 个差异是独立抽取的并且近似服从正态分布,在模型 A 和 B 具有相等性能的零假设下,我们可以根据 Student's t 检验计算具有 k-1 个自由度的以下 t 统计量:

其中,计算模型性能之间的差异在第 i 次迭代中的差异,,并且代表分类器性能之间的平均差异,.

计算出 t 统计量后,我们可以计算 p 值并将其与我们选择的显著性水平(例如)进行比较,例如,。如果 p 值小于,则我们拒绝零假设,并认为这两个模型之间存在显著差异。

此方法的问题以及不推荐在实践中使用它的原因是它违反了 Student's t 检验的一个假设 [1]

  • 模型性能之间的差异()不是正态分布的,因为不是独立的
  • 这些本身也不是独立的,因为训练集重叠

参考文献

  • [1] Dietterich TG (1998) Approximate Statistical Tests for Comparing Supervised Classification Learning Algorithms. Neural Comput 10:1895–1923.

示例 1 - K 折交叉验证配对 t 检验

假设我们要比较两种分类算法:逻辑回归和决策树算法

from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from mlxtend.data import iris_data
from sklearn.model_selection import train_test_split


X, y = iris_data()
clf1 = LogisticRegression(random_state=1)
clf2 = DecisionTreeClassifier(random_state=1)

X_train, X_test, y_train, y_test = \
    train_test_split(X, y, test_size=0.25,
                     random_state=123)

score1 = clf1.fit(X_train, y_train).score(X_test, y_test)
score2 = clf2.fit(X_train, y_train).score(X_test, y_test)

print('Logistic regression accuracy: %.2f%%' % (score1*100))
print('Decision tree accuracy: %.2f%%' % (score2*100))
Logistic regression accuracy: 97.37%
Decision tree accuracy: 94.74%

请注意,这些准确率值不用于配对 t 检验程序中,因为在重采样过程中会生成新的测试/训练分割;以上值仅用于直观说明。

现在,我们假设显著性阈值为用于拒绝两个算法在数据集上表现相同的零假设,并进行 K 折交叉验证 t 检验

from mlxtend.evaluate import paired_ttest_kfold_cv


t, p = paired_ttest_kfold_cv(estimator1=clf1,
                              estimator2=clf2,
                              X=X, y=y,
                              random_seed=1)

print('t statistic: %.3f' % t)
print('p value: %.3f' % p)
t statistic: -1.861
p value: 0.096

因为,我们无法拒绝零假设,并可能得出结论:这两种算法的性能没有显著差异。

虽然通常不建议在未进行多重假设检验校正的情况下多次应用统计检验,但让我们看一个示例,其中决策树算法被限制产生非常简单的决策边界,这将导致相对较差的性能

clf2 = DecisionTreeClassifier(random_state=1, max_depth=1)

score2 = clf2.fit(X_train, y_train).score(X_test, y_test)
print('Decision tree accuracy: %.2f%%' % (score2*100))


t, p = paired_ttest_kfold_cv(estimator1=clf1,
                             estimator2=clf2,
                             X=X, y=y,
                             random_seed=1)

print('t statistic: %.3f' % t)
print('p value: %.3f' % p)
Decision tree accuracy: 63.16%
t statistic: 13.491
p value: 0.000

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

API

paired_ttest_kfold_cv(estimator1, estimator2, X, y, cv=10, scoring=None, shuffle=False, random_seed=None)

实现 K 折配对 t 检验程序以比较两个模型的性能。

参数

  • estimator1 : scikit-learn 分类器或回归器

  • estimator2 : scikit-learn 分类器或回归器

  • X : {array-like, sparse matrix}, 形状 = [样本数, 特征数]

    训练向量,其中 n_samples 是样本数,n_features 是特征数。

  • y : array-like, 形状 = [样本数]

    目标值。

  • cv : int (默认: 10)

    交叉验证过程的分割数和迭代次数

  • scoring : str, callable, 或 None (默认: None)

    如果为 None(默认),对 sklearn 分类器使用 'accuracy',对 sklearn 回归器使用 'r2'。如果为 str,使用 sklearn 评分指标字符串标识符,例如分类器的 {accuracy, f1, precision, recall, roc_auc},回归器的 {'mean_absolute_error', 'mean_squared_error'/'neg_mean_squared_error', 'median_absolute_error', 'r2'}。如果提供了一个可调用对象或函数,它必须符合 sklearn 的签名 scorer(estimator, X, y);更多信息请参阅 https://scikit-learn.cn/stable/modules/generated/sklearn.metrics.make_scorer.html。

  • shuffle : bool (默认: True)

    是否打乱数据集以生成 K 折分割。

  • random_seed : int 或 None (默认: None)

    用于打乱数据集生成 K 折分割的随机种子。如果 shuffle=False,则忽略。

返回值

  • t : float

    t 统计量

  • pvalue : float

    双尾 p 值。如果选择的显著性水平大于 p 值,则我们拒绝零假设,并认为所比较的两个模型之间存在显著差异。

示例

有关用法示例,请参阅 https://mlxtend.cn/mlxtend/user_guide/evaluate/paired_ttest_kfold_cv/