跳至主要内容
Ctrl+K
scikit-learn homepage scikit-learn homepage
  • 安装
  • 用户指南
  • API
  • 示例
  • 社区
    • 入门
    • 发布历史
    • 术语表
    • 开发
    • 常见问题解答
    • 支持
    • 相关项目
    • 路线图
    • 治理
    • 关于我们
  • GitHub
  • 安装
  • 用户指南
  • API
  • 示例
  • 社区
  • 入门
  • 发布历史
  • 术语表
  • 开发
  • 常见问题解答
  • 支持
  • 相关项目
  • 路线图
  • 治理
  • 关于我们
  • GitHub

章节导航

  • 发布亮点
    • scikit-learn 1.5 版本亮点
    • scikit-learn 1.4 版本亮点
    • scikit-learn 1.3 版本亮点
    • scikit-learn 1.2 版本亮点
    • scikit-learn 1.1 版本亮点
    • scikit-learn 1.0 版本亮点
    • scikit-learn 0.24 版本亮点
    • scikit-learn 0.23 版本亮点
    • scikit-learn 0.22 版本亮点
  • 双聚类
    • 谱双聚类算法演示
    • 谱共聚类算法演示
    • 使用谱共聚类算法对文档进行双聚类
  • 校准
    • 分类器校准比较
    • 概率校准曲线
    • 三类分类的概率校准
    • 分类器的概率校准
  • 分类
    • 分类器比较
    • 带有协方差椭圆的线性判别分析和二次判别分析
    • 用于分类的正态、Ledoit-Wolf 和 OAS 线性判别分析
    • 绘制分类概率
    • 识别手写数字
  • 聚类
    • 手写数字数据上的 K 均值聚类演示
    • 图像中硬币的结构化 Ward 层次聚类演示
    • 均值漂移聚类算法演示
    • 聚类性能评估中的机会调整
    • 有结构和无结构的凝聚层次聚类
    • 使用不同度量的凝聚层次聚类
    • K 均值++ 初始化示例
    • 二分 K 均值和常规 K 均值性能比较
    • 使用 K 均值进行颜色量化
    • 比较 BIRCH 和 MiniBatchKMeans
    • 在玩具数据集上比较不同的聚类算法
    • 在玩具数据集上比较不同的层次链接方法
    • 比较 K 均值和 MiniBatchKMeans 聚类算法
    • DBSCAN 聚类算法演示
    • HDBSCAN 聚类算法演示
    • OPTICS 聚类算法演示
    • 亲和传播聚类算法演示
    • K 均值假设演示
    • 对 K 均值初始化影响的经验评估
    • 特征凝聚
    • 特征凝聚与单变量选择
    • 层次聚类:结构化与非结构化 Ward
    • 归纳聚类
    • K 均值聚类
    • 人脸部件字典的在线学习
    • 绘制层次聚类树状图
    • 将希腊硬币图片分割成区域
    • 使用 KMeans 聚类的轮廓分析选择聚类数量
    • 用于图像分割的谱聚类
    • 数字二维嵌入上的各种凝聚层次聚类
    • 矢量量化示例
  • 协方差估计
    • Ledoit-Wolf 与 OAS 估计
    • 鲁棒协方差估计和马氏距离相关性
    • 鲁棒与经验协方差估计
    • 收缩协方差估计:LedoitWolf 与 OAS 和最大似然
    • 稀疏逆协方差估计
  • 交叉分解
    • 比较交叉分解方法
    • 主成分回归与偏最小二乘回归
  • 数据集示例
    • 绘制随机生成的分类数据集
    • 绘制随机生成的多分支数据集
    • 数字数据集
    • 鸢尾花数据集
  • 决策树
    • 决策树回归
    • 多输出决策树回归
    • 绘制在鸢尾花数据集上训练的决策树的决策面
    • 使用成本复杂度修剪后修剪决策树
    • 了解决策树结构
  • 分解
    • 使用 FastICA 进行盲源分离
    • 比较 LDA 和 PCA 对鸢尾花数据集的二维投影
    • 人脸数据集分解
    • 因子分析(带旋转)以可视化模式
    • 二维点云上的 FastICA
    • 使用字典学习进行图像降噪
    • 增量 PCA
    • 核 PCA
    • 使用概率 PCA 和因子分析 (FA) 进行模型选择
    • 使用鸢尾花数据集的 PCA 示例
    • 使用预先计算的字典进行稀疏编码
  • 开发估计器
    • __sklearn_is_fitted__ 作为开发者 API
  • 集成方法
    • 梯度提升中的分类特征支持
    • 使用堆叠组合预测器
    • 比较随机森林和直方图梯度提升模型
    • 比较随机森林和多输出元估计器
    • 使用 AdaBoost 的决策树回归
    • 梯度提升中的提前停止
    • 使用树的森林进行特征重要性分析
    • 使用树的集成进行特征转换
    • 直方图梯度提升树中的特征
    • 梯度提升袋外估计
    • 梯度提升回归
    • 梯度提升正则化
    • 使用完全随机树进行哈希特征转换
    • IsolationForest 示例
    • 单调约束
    • 多类 AdaBoosted 决策树
    • 随机森林的袋外误差
    • 使用树的并行森林进行像素重要性分析
    • 绘制 VotingClassifier 计算的类概率
    • 绘制单个和投票回归预测
    • 绘制 VotingClassifier 的决策边界
    • 绘制鸢尾花数据集上树的集成决策面
    • 梯度提升回归的预测区间
    • 单个估计器与 Bagging:偏差-方差分解
    • 二类 AdaBoost
  • 基于真实世界数据集的示例
    • 压缩感知:使用 L1 先验(Lasso)进行断层扫描重建
    • 使用特征脸和 SVM 的人脸识别示例
    • 使用核 PCA 进行图像降噪
    • 时间序列预测的滞后特征
    • 模型复杂度影响
    • 文本文档的离核分类
    • 对真实数据集进行异常值检测
    • 预测延迟
    • 物种分布模型
    • 与时间相关的特征工程
    • 使用非负矩阵分解和潜在狄利克雷分配进行主题提取
    • 可视化股票市场结构
    • 维基百科主特征向量
  • 特征选择
    • F 检验和互信息的比较
    • 基于模型和顺序的特征选择
    • 管道 ANOVA SVM
    • 递归特征消除
    • 使用交叉验证的递归特征消除
    • 单变量特征选择
  • 高斯混合模型
    • 变分贝叶斯高斯混合的集中先验类型分析
    • 高斯混合的密度估计
    • GMM 初始化方法
    • GMM 协方差
    • 高斯混合模型椭球
    • 高斯混合模型选择
    • 高斯混合模型正弦曲线
  • 用于机器学习的高斯过程
    • 高斯过程回归 (GPR) 估计数据噪声水平的能力
    • 比较核岭回归和高斯过程回归
    • 使用高斯过程回归 (GPR) 预测莫纳罗亚数据集上的 CO2 水平
    • 高斯过程回归:基本介绍性示例
    • 鸢尾花数据集上的高斯过程分类 (GPC)
    • 离散数据结构上的高斯过程
    • 在 XOR 数据集上说明高斯过程分类 (GPC)
    • 说明不同核的先验和后验高斯过程
    • 高斯过程分类 (GPC) 的等概率线
    • 使用高斯过程分类 (GPC) 进行概率预测
  • 广义线性模型
    • 比较线性贝叶斯回归器
    • 比较各种在线求解器
    • 使用贝叶斯岭回归进行曲线拟合
    • 随机梯度下降的提前停止
    • 使用预先计算的格拉姆矩阵和加权样本拟合弹性网络
    • 在具有强异常值的 数据集上 HuberRegressor 与 Ridge 的比较
    • 使用多任务 Lasso 进行联合特征选择
    • 逻辑回归中的 L1 惩罚和稀疏性
    • 基于 L1 的稀疏信号模型
    • Lasso 和弹性网络
    • 使用信息准则进行 Lasso 模型选择
    • Lasso 模型选择:AIC-BIC / 交叉验证
    • 在密集和稀疏数据上使用 Lasso
    • 使用 LARS 的 Lasso 路径
    • 线性回归示例
    • 逻辑回归 3 类分类器
    • 逻辑函数
    • 使用多项式逻辑 + L1 进行 MNIST 分类
    • 在 20newsgroups 上进行多类稀疏逻辑回归
    • 非负最小二乘
    • 使用随机梯度下降的一类 SVM 与一类 SVM 的比较
    • 普通最小二乘和岭回归方差
    • 正交匹配追踪
    • 绘制岭系数作为正则化的函数
    • 在 iris 数据集上绘制多类 SGD
    • 绘制多项式和一对多逻辑回归
    • 泊松回归和非正态损失
    • 多项式和样条插值
    • 分位数回归
    • L1-逻辑回归的正则化路径
    • 岭系数作为 L2 正则化的函数
    • 鲁棒线性估计器拟合
    • 使用 RANSAC 进行鲁棒线性模型估计
    • SGD:最大间隔分离超平面
    • SGD:惩罚
    • SGD:加权样本
    • SGD:凸损失函数
    • 稀疏性示例:仅拟合特征 1 和 2
    • Theil-Sen 回归
    • 保险索赔的 Tweedie 回归
  • 检验
    • 线性模型系数解释中的常见陷阱
    • 机器学习推断因果效应的失败
    • 偏依赖和个体条件期望图
    • 排列重要性与随机森林特征重要性 (MDI)
    • 具有多重共线性或相关特征的排列重要性
  • 核近似
    • 使用多项式核近似进行可扩展学习
  • 流形学习
    • 比较流形学习方法
    • 在断开的球体上使用流形学习方法
    • 手写数字的流形学习:局部线性嵌入、Isomap…
    • 多维标度
    • 瑞士卷和瑞士洞还原
    • t-SNE:不同困惑度值对形状的影响
  • 其他
    • 使用偏依赖进行高级绘图
    • 比较玩具数据集上异常检测算法的异常检测
    • 比较核岭回归和 SVR
    • 显示管道
    • 显示估计器和复杂管道
    • 异常检测估计器的评估
    • RBF 核的显式特征映射近似
    • 使用多输出估计器进行人脸补全
    • 介绍 set_output API
    • 等距回归
    • 元数据路由
    • 多标签分类
    • 使用可视化 API 的 ROC 曲线
    • 使用随机投影进行嵌入的 Johnson-Lindenstrauss 界限
    • 使用显示对象进行可视化
  • 缺失值插补
    • 在构建估计器之前插补缺失值
    • 使用 IterativeImputer 的变体插补缺失值
  • 模型选择
    • 平衡模型复杂度和交叉验证得分
    • 类似然比用于衡量分类性能
    • 比较随机搜索和网格搜索用于超参数估计
    • 比较网格搜索和逐次减半
    • 混淆矩阵
    • 使用交叉验证的网格搜索的自定义重拟合策略
    • 演示 cross_val_score 和 GridSearchCV 上的多指标评估
    • 检测错误权衡 (DET) 曲线
    • 多类接收者操作特征 (ROC)
    • 嵌套与非嵌套交叉验证
    • 绘制交叉验证预测
    • 绘制学习曲线并检查模型的可扩展性
    • 绘制验证曲线
    • 事后调整决策函数的截止点
    • 为成本敏感学习调整决策阈值
    • 精确率-召回率
    • 使用交叉验证的接收者操作特征 (ROC)
    • 文本特征提取和评估的示例管道
    • 使用网格搜索对模型进行统计比较
    • 逐次减半迭代
    • 使用置换测试分类得分的显著性
    • 训练误差与测试误差
    • 欠拟合与过拟合
    • 可视化 scikit-learn 中的交叉验证行为
  • 多类方法
    • 多类训练元估计器的概述
  • 多输出方法
    • 使用分类器链进行多标签分类
  • 最近邻
    • TSNE 中的近似最近邻
    • 缓存最近邻
    • 比较有和没有邻域成分分析的最近邻
    • 使用邻域成分分析进行降维
    • 物种分布的核密度估计
    • 核密度估计
    • 最近质心分类
    • 最近邻分类
    • 最近邻回归
    • 邻域成分分析图示
    • 使用局部离群因子 (LOF) 进行新颖性检测
    • 使用局部离群因子 (LOF) 进行离群点检测
    • 简单的 1D 核密度估计
  • 神经网络
    • 比较 MLPClassifier 的随机学习策略
    • 用于数字分类的受限玻尔兹曼机特征
    • 在多层感知器中改变正则化
    • MNIST 上 MLP 权重的可视化
  • 管道和复合估计器
    • 具有异构数据源的列转换器
    • 具有混合类型的列转换器
    • 连接多个特征提取方法
    • 在回归模型中转换目标的影响
    • 管道化:将 PCA 和逻辑回归链接起来
    • 使用 Pipeline 和 GridSearchCV 选择降维
  • 预处理
    • 比较不同缩放器对包含异常值的数据的影响
    • 比较目标编码器和其他编码器
    • 演示 KBinsDiscretizer 的不同策略
    • 特征离散化
    • 特征缩放的重要性
    • 将数据映射到正态分布
    • 目标编码器的内部交叉拟合
    • 使用 KBinsDiscretizer 对连续特征进行离散化
  • 半监督分类
    • 半监督分类器与 SVM 在 Iris 数据集上的决策边界
    • 改变自训练阈值的影响
    • 标签传播数字主动学习
    • 标签传播数字:演示性能
    • 标签传播学习复杂结构
    • 文本数据集上的半监督分类
  • 支持向量机
    • 使用非线性核(RBF)的一类 SVM
    • 使用不同的 SVM 核绘制分类边界
    • 在鸢尾花数据集上绘制不同的 SVM 分类器
    • 绘制 LinearSVC 中的支持向量
    • RBF SVM 参数
    • SVM 边界示例
    • SVM 平局情况示例
    • 使用自定义核的 SVM
    • SVM-Anova:使用单变量特征选择的 SVM
    • SVM:最大间隔分离超平面
    • SVM:不平衡类别的分离超平面
    • SVM:加权样本
    • 为 SVC 缩放正则化参数
    • 使用线性核和非线性核的支持向量回归 (SVR)
  • 教程练习
    • 糖尿病数据集上的交叉验证练习
    • 数字分类练习
    • SVM 练习
  • 处理文本文档
    • 使用稀疏特征对文本文档进行分类
    • 使用 k-means 对文本文档进行聚类
    • FeatureHasher 和 DictVectorizer 比较
  • 示例
  • 模型选择
  • 统计...

使用网格搜索进行模型的统计比较#

本示例说明如何使用 GridSearchCV 对使用训练和评估的模型的性能进行统计比较。

我们将首先模拟月牙形数据(其中类之间的理想分离是非线性的),并向其添加适度的噪声。数据点将属于两个可能的类之一,由两个特征预测。我们将为每个类模拟 50 个样本。

import matplotlib.pyplot as plt
import seaborn as sns

from sklearn.datasets import make_moons

X, y = make_moons(noise=0.352, random_state=1, n_samples=100)

sns.scatterplot(
    x=X[:, 0], y=X[:, 1], hue=y, marker="o", s=25, edgecolor="k", legend=False
).set_title("Data")
plt.show()
Data

我们将比较 SVC 估计器的性能,这些估计器在其 kernel 参数上有所不同,以确定此超参数的哪种选择最能预测我们模拟的数据。我们将使用 RepeatedStratifiedKFold 评估模型的性能,重复 10 次 10 折分层交叉验证,在每次重复中使用不同的数据随机化。性能将使用 roc_auc_score 进行评估。

from sklearn.model_selection import GridSearchCV, RepeatedStratifiedKFold
from sklearn.svm import SVC

param_grid = [
    {"kernel": ["linear"]},
    {"kernel": ["poly"], "degree": [2, 3]},
    {"kernel": ["rbf"]},
]

svc = SVC(random_state=0)

cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=10, random_state=0)

search = GridSearchCV(estimator=svc, param_grid=param_grid, scoring="roc_auc", cv=cv)
search.fit(X, y)
GridSearchCV(cv=RepeatedStratifiedKFold(n_repeats=10, n_splits=10, random_state=0),
             estimator=SVC(random_state=0),
             param_grid=[{'kernel': ['linear']},
                         {'degree': [2, 3], 'kernel': ['poly']},
                         {'kernel': ['rbf']}],
             scoring='roc_auc')
在 Jupyter 环境中,请重新运行此单元格以显示 HTML 表示或信任笔记本。
在 GitHub 上,HTML 表示无法呈现,请尝试使用 nbviewer.org 加载此页面。
GridSearchCV(cv=RepeatedStratifiedKFold(n_repeats=10, n_splits=10, random_state=0),
             estimator=SVC(random_state=0),
             param_grid=[{'kernel': ['linear']},
                         {'degree': [2, 3], 'kernel': ['poly']},
                         {'kernel': ['rbf']}],
             scoring='roc_auc')
SVC(random_state=0)
SVC(random_state=0)


现在我们可以检查搜索结果,按其 mean_test_score 排序。

import pandas as pd

results_df = pd.DataFrame(search.cv_results_)
results_df = results_df.sort_values(by=["rank_test_score"])
results_df = results_df.set_index(
    results_df["params"].apply(lambda x: "_".join(str(val) for val in x.values()))
).rename_axis("kernel")
results_df[["params", "rank_test_score", "mean_test_score", "std_test_score"]]
params rank_test_score mean_test_score std_test_score
kernel
rbf {'kernel': 'rbf'} 1 0.9400 0.079297
linear {'kernel': 'linear'} 2 0.9300 0.077846
3_poly {'degree': 3, 'kernel': 'poly'} 3 0.9044 0.098776
2_poly {'degree': 2, 'kernel': 'poly'} 4 0.6852 0.169106


我们可以看到,使用 'rbf' 核的估计器表现最佳,紧随其后的是 'linear'。使用 'poly' 核的两个估计器表现较差,其中使用二阶多项式的估计器比所有其他模型的性能都要低得多。

通常,分析到此结束,但故事的另一半却缺失了。 GridSearchCV 的输出不提供有关模型之间差异确定性的信息。我们不知道这些差异是否具有 **统计学** 意义。为了评估这一点,我们需要进行统计检验。具体来说,为了对比两个模型的性能,我们应该对它们的 AUC 分数进行统计比较。由于我们重复了 10 次 10 折交叉验证,因此每个模型有 100 个样本(AUC 分数)。

但是,模型的分数并不独立:所有模型都在 **相同** 的 100 个分区上进行评估,这增加了模型性能之间的相关性。由于数据的一些分区可能使所有模型都特别容易或难以找到类别的区分,因此模型分数将协变。

让我们通过绘制每个折叠中所有模型的性能并计算折叠之间模型的相关性来检查这种分区效应。

# create df of model scores ordered by performance
model_scores = results_df.filter(regex=r"split\d*_test_score")

# plot 30 examples of dependency between cv fold and AUC scores
fig, ax = plt.subplots()
sns.lineplot(
    data=model_scores.transpose().iloc[:30],
    dashes=False,
    palette="Set1",
    marker="o",
    alpha=0.5,
    ax=ax,
)
ax.set_xlabel("CV test fold", size=12, labelpad=10)
ax.set_ylabel("Model AUC", size=12)
ax.tick_params(bottom=True, labelbottom=False)
plt.show()

# print correlation of AUC scores across folds
print(f"Correlation of models:\n {model_scores.transpose().corr()}")
plot grid search stats
Correlation of models:
 kernel       rbf    linear    3_poly    2_poly
kernel
rbf     1.000000  0.882561  0.783392  0.351390
linear  0.882561  1.000000  0.746492  0.298688
3_poly  0.783392  0.746492  1.000000  0.355440
2_poly  0.351390  0.298688  0.355440  1.000000

我们可以观察到,模型的性能高度依赖于折叠。

因此,如果我们假设样本之间相互独立,我们将低估统计检验中计算的方差,从而增加假阳性错误的数量(即,在模型之间不存在这种差异的情况下检测到显著差异)[1]。

针对这些情况,已经开发出几种方差校正统计检验。在本示例中,我们将展示如何在两种不同的统计框架下实现其中之一(即所谓的 Nadeau 和 Bengio 校正的 t 检验):频率论和贝叶斯。

比较两个模型:频率论方法#

我们可以首先问:“第一个模型是否显著优于第二个模型(按 mean_test_score 排名)?”

为了使用频率论方法回答这个问题,我们可以运行配对 t 检验并计算 p 值。这在预测文献中也被称为 Diebold-Mariano 检验 [5]。已经开发出许多这种 t 检验的变体来解释上一节中描述的“样本非独立性问题”。我们将使用经证明获得最高可重复性分数(它衡量模型在评估相同数据集的不同随机分区时的性能有多相似)同时保持低假阳性率和假阴性率的变体:Nadeau 和 Bengio 校正的 t 检验 [2],它使用 10 次重复的 10 折交叉验证 [3]。

此校正的配对 t 检验计算如下

t=1k⋅r∑i=1k∑j=1rxij(1k⋅r+ntestntrain)σ^2

其中 k 是折叠数,r 是交叉验证中的重复次数,x 是模型性能的差异,ntest 是用于测试的样本数,ntrain 是用于训练的样本数,σ^2 表示观察到的差异的方差。

让我们实现一个校正的右尾配对 t 检验,以评估第一个模型的性能是否显著优于第二个模型。我们的零假设是第二个模型的性能至少与第一个模型一样好。

import numpy as np
from scipy.stats import t


def corrected_std(differences, n_train, n_test):
    """Corrects standard deviation using Nadeau and Bengio's approach.

    Parameters
    ----------
    differences : ndarray of shape (n_samples,)
        Vector containing the differences in the score metrics of two models.
    n_train : int
        Number of samples in the training set.
    n_test : int
        Number of samples in the testing set.

    Returns
    -------
    corrected_std : float
        Variance-corrected standard deviation of the set of differences.
    """
    # kr = k times r, r times repeated k-fold crossvalidation,
    # kr equals the number of times the model was evaluated
    kr = len(differences)
    corrected_var = np.var(differences, ddof=1) * (1 / kr + n_test / n_train)
    corrected_std = np.sqrt(corrected_var)
    return corrected_std


def compute_corrected_ttest(differences, df, n_train, n_test):
    """Computes right-tailed paired t-test with corrected variance.

    Parameters
    ----------
    differences : array-like of shape (n_samples,)
        Vector containing the differences in the score metrics of two models.
    df : int
        Degrees of freedom.
    n_train : int
        Number of samples in the training set.
    n_test : int
        Number of samples in the testing set.

    Returns
    -------
    t_stat : float
        Variance-corrected t-statistic.
    p_val : float
        Variance-corrected p-value.
    """
    mean = np.mean(differences)
    std = corrected_std(differences, n_train, n_test)
    t_stat = mean / std
    p_val = t.sf(np.abs(t_stat), df)  # right-tailed t-test
    return t_stat, p_val
model_1_scores = model_scores.iloc[0].values  # scores of the best model
model_2_scores = model_scores.iloc[1].values  # scores of the second-best model

differences = model_1_scores - model_2_scores

n = differences.shape[0]  # number of test sets
df = n - 1
n_train = len(list(cv.split(X, y))[0][0])
n_test = len(list(cv.split(X, y))[0][1])

t_stat, p_val = compute_corrected_ttest(differences, df, n_train, n_test)
print(f"Corrected t-value: {t_stat:.3f}\nCorrected p-value: {p_val:.3f}")
Corrected t-value: 0.750
Corrected p-value: 0.227

我们可以将校正的 t 值和 p 值与未校正的值进行比较。

t_stat_uncorrected = np.mean(differences) / np.sqrt(np.var(differences, ddof=1) / n)
p_val_uncorrected = t.sf(np.abs(t_stat_uncorrected), df)

print(
    f"Uncorrected t-value: {t_stat_uncorrected:.3f}\n"
    f"Uncorrected p-value: {p_val_uncorrected:.3f}"
)
Uncorrected t-value: 2.611
Uncorrected p-value: 0.005

使用 p=0.05 的传统显著性 alpha 水平,我们观察到未校正的 t 检验得出结论,第一个模型显著优于第二个模型。

相反,使用校正方法,我们无法检测到这种差异。

但是,在后一种情况下,频率论方法并没有让我们得出结论,第一个模型和第二个模型的性能相同。如果我们想断言这一点,我们需要使用贝叶斯方法。

比较两个模型:贝叶斯方法#

我们可以使用贝叶斯估计来计算第一个模型优于第二个模型的概率。贝叶斯估计将输出两个模型性能差异的平均值 μ 所遵循的分布。

为了获得后验分布,我们需要定义一个先验,它在查看数据之前对平均值的分布进行建模,并将其乘以一个似然函数,该函数计算给定平均值差异可能取的值时,观察到的差异的可能性。

贝叶斯估计可以以多种形式执行以回答我们的问题,但在此示例中,我们将实现 Benavoli 及其同事建议的方法 [4]。

使用闭合形式表达式定义后验的一种方法是选择一个与似然函数共轭的先验。Benavoli 及其同事 [4] 表明,在比较两个分类器的性能时,我们可以将先验建模为正态-伽马分布(均值和方差均未知),它与正态似然函数共轭,从而将后验表示为正态分布。从这个正态后验中边缘化方差,我们可以将平均值参数的后验定义为学生 t 分布。具体来说

St(μ;n−1,x―,(1n+ntestntrain)σ^2)

其中 n 是样本总数,x― 代表分数的平均差异,ntest 是用于测试的样本数量,ntrain 是用于训练的样本数量,σ^2 代表观察到的差异的方差。

请注意,我们也在我们的贝叶斯方法中使用 Nadeau 和 Bengio 修正的方差。

让我们计算并绘制后验分布

# initialize random variable
t_post = t(
    df, loc=np.mean(differences), scale=corrected_std(differences, n_train, n_test)
)

让我们绘制后验分布

x = np.linspace(t_post.ppf(0.001), t_post.ppf(0.999), 100)

plt.plot(x, t_post.pdf(x))
plt.xticks(np.arange(-0.04, 0.06, 0.01))
plt.fill_between(x, t_post.pdf(x), 0, facecolor="blue", alpha=0.2)
plt.ylabel("Probability density")
plt.xlabel(r"Mean difference ($\mu$)")
plt.title("Posterior distribution")
plt.show()
Posterior distribution

我们可以通过计算后验分布从零到无穷大的曲线下面积来计算第一个模型优于第二个模型的概率。反之亦然:我们可以通过计算从负无穷大到零的曲线下面积来计算第二个模型优于第一个模型的概率。

better_prob = 1 - t_post.cdf(0)

print(
    f"Probability of {model_scores.index[0]} being more accurate than "
    f"{model_scores.index[1]}: {better_prob:.3f}"
)
print(
    f"Probability of {model_scores.index[1]} being more accurate than "
    f"{model_scores.index[0]}: {1 - better_prob:.3f}"
)
Probability of rbf being more accurate than linear: 0.773
Probability of linear being more accurate than rbf: 0.227

与频率论方法相比,我们可以计算一个模型优于另一个模型的概率。

请注意,我们获得的结果与频率论方法中的结果相似。鉴于我们对先验的选择,我们实际上执行了相同的计算,但我们被允许做出不同的断言。

实际等效区域#

有时我们有兴趣确定我们的模型具有等效性能的概率,其中“等效”以实际方式定义。一种朴素的方法 [4] 将是当估计器的精度差异小于 1% 时将它们定义为实际等效。但我们也可以考虑我们试图解决的问题来定义这种实际等效性。例如,精度差异 5% 将意味着销售额增加 1000 美元,我们认为任何高于此的数量对于我们的业务都是相关的。

在这个例子中,我们将定义实际等效区域 (ROPE) 为 [−0.01,0.01]。也就是说,如果两个模型的性能差异小于 1%,我们将认为它们在实践中是等效的。

为了计算分类器在实践中等效的概率,我们计算后验分布在 ROPE 区间上的曲线下面积

rope_interval = [-0.01, 0.01]
rope_prob = t_post.cdf(rope_interval[1]) - t_post.cdf(rope_interval[0])

print(
    f"Probability of {model_scores.index[0]} and {model_scores.index[1]} "
    f"being practically equivalent: {rope_prob:.3f}"
)
Probability of rbf and linear being practically equivalent: 0.432

我们可以绘制后验分布在 ROPE 区间上的分布情况

x_rope = np.linspace(rope_interval[0], rope_interval[1], 100)

plt.plot(x, t_post.pdf(x))
plt.xticks(np.arange(-0.04, 0.06, 0.01))
plt.vlines([-0.01, 0.01], ymin=0, ymax=(np.max(t_post.pdf(x)) + 1))
plt.fill_between(x_rope, t_post.pdf(x_rope), 0, facecolor="blue", alpha=0.2)
plt.ylabel("Probability density")
plt.xlabel(r"Mean difference ($\mu$)")
plt.title("Posterior distribution under the ROPE")
plt.show()
Posterior distribution under the ROPE

正如 [4] 中所建议的,我们可以使用与频率论方法相同的标准进一步解释这些概率:落在 ROPE 内部的概率是否大于 95%(alpha 值为 5%)?在这种情况下,我们可以得出结论,这两个模型在实践中是等效的。

贝叶斯估计方法还允许我们计算我们对差异估计的不确定性。这可以使用可信区间来计算。对于给定的概率,它们显示了估计量(在本例中是性能的平均差异)可以取值的范围。例如,50% 的可信区间 [x, y] 告诉我们,模型之间真实(平均)性能差异在 x 和 y 之间的概率为 50%。

让我们使用 50%、75% 和 95% 来确定数据的可信区间

cred_intervals = []
intervals = [0.5, 0.75, 0.95]

for interval in intervals:
    cred_interval = list(t_post.interval(interval))
    cred_intervals.append([interval, cred_interval[0], cred_interval[1]])

cred_int_df = pd.DataFrame(
    cred_intervals, columns=["interval", "lower value", "upper value"]
).set_index("interval")
cred_int_df
下限 上限
区间
0.50 0.000977 0.019023
0.75 -0.005422 0.025422
0.95 -0.016445 0.036445


如表所示,模型之间真实平均差异在 0.000977 和 0.019023 之间的概率为 50%,在 -0.005422 和 0.025422 之间的概率为 70%,在 -0.016445 和 0.036445 之间的概率为 95%。

所有模型的成对比较:频率论方法#

我们也可能对比较我们所有使用 GridSearchCV 评估的模型的性能感兴趣。在这种情况下,我们将多次运行我们的统计检验,这会导致我们遇到 多重比较问题。

解决这个问题有很多方法,但一种标准方法是应用 Bonferroni 校正。Bonferroni 可以通过将 p 值乘以我们正在测试的比较次数来计算。

让我们使用修正的 t 检验来比较模型的性能

from itertools import combinations
from math import factorial

n_comparisons = factorial(len(model_scores)) / (
    factorial(2) * factorial(len(model_scores) - 2)
)
pairwise_t_test = []

for model_i, model_k in combinations(range(len(model_scores)), 2):
    model_i_scores = model_scores.iloc[model_i].values
    model_k_scores = model_scores.iloc[model_k].values
    differences = model_i_scores - model_k_scores
    t_stat, p_val = compute_corrected_ttest(differences, df, n_train, n_test)
    p_val *= n_comparisons  # implement Bonferroni correction
    # Bonferroni can output p-values higher than 1
    p_val = 1 if p_val > 1 else p_val
    pairwise_t_test.append(
        [model_scores.index[model_i], model_scores.index[model_k], t_stat, p_val]
    )

pairwise_comp_df = pd.DataFrame(
    pairwise_t_test, columns=["model_1", "model_2", "t_stat", "p_val"]
).round(3)
pairwise_comp_df
model_1 model_2 t_stat p_val
0 rbf linear 0.750 1.000
1 rbf 3_poly 1.657 0.302
2 rbf 2_poly 4.565 0.000
3 linear 3_poly 1.111 0.807
4 linear 2_poly 4.276 0.000
5 3_poly 2_poly 3.851 0.001


我们观察到,在对多重比较进行校正后,唯一与其他模型显著不同的模型是 '2_poly'。 'rbf'(由 GridSearchCV 排名第一的模型)与 'linear' 或 '3_poly' 没有显著差异。

所有模型的成对比较:贝叶斯方法#

当使用贝叶斯估计来比较多个模型时,我们不需要对多重比较进行校正(有关原因,请参见 [4])。

我们可以像第一部分一样进行成对比较

pairwise_bayesian = []

for model_i, model_k in combinations(range(len(model_scores)), 2):
    model_i_scores = model_scores.iloc[model_i].values
    model_k_scores = model_scores.iloc[model_k].values
    differences = model_i_scores - model_k_scores
    t_post = t(
        df, loc=np.mean(differences), scale=corrected_std(differences, n_train, n_test)
    )
    worse_prob = t_post.cdf(rope_interval[0])
    better_prob = 1 - t_post.cdf(rope_interval[1])
    rope_prob = t_post.cdf(rope_interval[1]) - t_post.cdf(rope_interval[0])

    pairwise_bayesian.append([worse_prob, better_prob, rope_prob])

pairwise_bayesian_df = pd.DataFrame(
    pairwise_bayesian, columns=["worse_prob", "better_prob", "rope_prob"]
).round(3)

pairwise_comp_df = pairwise_comp_df.join(pairwise_bayesian_df)
pairwise_comp_df
model_1 model_2 t_stat p_val worse_prob better_prob rope_prob
0 rbf linear 0.750 1.000 0.068 0.500 0.432
1 rbf 3_poly 1.657 0.302 0.018 0.882 0.100
2 rbf 2_poly 4.565 0.000 0.000 1.000 0.000
3 linear 3_poly 1.111 0.807 0.063 0.750 0.187
4 linear 2_poly 4.276 0.000 0.000 1.000 0.000
5 3_poly 2_poly 3.851 0.001 0.000 1.000 0.000


使用贝叶斯方法,我们可以计算一个模型比另一个模型表现更好、更差或在实践中等效的概率。

结果表明,由 GridSearchCV 排名第一的模型 'rbf' 比 'linear' 差的概率约为 6.8%,比 '3_poly' 差的概率为 1.8%。 'rbf' 和 'linear' 在实践中等效的概率为 43%,而 'rbf' 和 '3_poly' 在实践中等效的概率为 10%。

与使用频率论方法获得的结论类似,所有模型比 '2_poly' 好的概率为 100%,并且没有模型与后者在实践中具有等效的性能。

要点#

  • 性能指标的微小差异可能很容易被证明仅仅是偶然发生的,而不是因为一个模型比另一个模型系统地预测得更好。如本例所示,统计数据可以告诉你这种情况发生的可能性。

  • 在统计比较两个在 GridSearchCV 中评估的模型的性能时,有必要校正计算的方差,因为模型的分数彼此之间并不独立。

  • 使用(方差校正)配对 t 检验的频率论方法可以告诉我们,一个模型的性能是否比另一个模型好,其确定性程度高于偶然性。

  • 贝叶斯方法可以提供一个模型比另一个模型更好、更差或在实践中等效的概率。它还可以告诉我们,我们对知道模型的真实差异落在某个特定值范围内的信心程度。

  • 如果对多个模型进行统计比较,则在使用频率论方法时需要进行多重比较校正。

参考文献

[1]

Dietterich, T. G. (1998). 用于比较监督分类学习算法的近似统计检验. 神经计算,10(7)。

[2]

Nadeau, C., & Bengio, Y. (2000). 泛化误差的推断. 在神经信息处理系统进展中。

[3]

Bouckaert, R. R., & Frank, E. (2004). 评估比较学习算法的显著性检验的可重复性. 在亚太地区知识发现与数据挖掘会议上。

[4] (1,2,3,4,5)

Benavoli, A., Corani, G., Demšar, J., & Zaffalon, M. (2017). 是时候改变了:通过贝叶斯分析比较多个分类器的教程. 机器学习研究杂志,18(1)。请参见本文附带的 Python 库 此处。

[5]

Diebold, F.X. & Mariano R.S. (1995). 比较预测精度 商业与经济统计杂志,20(1), 134-144。

脚本总运行时间:(0 分钟 1.611 秒)

相关示例

使用排列检验分类分数的显著性

使用排列检验分类分数的显著性

线性模型系数解释中的常见陷阱

线性模型系数解释中的常见陷阱

分类器校准的比较

分类器校准的比较

文本特征提取和评估的示例管道

文本特征提取和评估的示例管道

由 Sphinx-Gallery 生成的图库

上一页

文本特征提取和评估的示例管道

下一页

连续减半迭代

本页内容
  • 比较两个模型:频率论方法
  • 比较两个模型:贝叶斯方法
    • 实际等效区域
  • 所有模型的成对比较:频率论方法
  • 所有模型的成对比较:贝叶斯方法
  • 要点
下载源代码
下载 Jupyter 笔记本
Launch JupyterLite
Launch binder

© Copyright 2007 - 2024, scikit-learn 开发者 (BSD 许可证)。