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

部分导航

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

注意

转到页面底部 下载完整示例代码,或通过 JupyterLite 或 Binder 在浏览器中运行此示例。

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

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

# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause

我们将从模拟月牙形数据(类与类之间的理想分隔是非线性的)开始,并向其中添加适量的噪声。数据点属于两个类别中的一个,需根据两个特征进行预测。我们将为每个类别模拟 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

我们将比较不同 kernel 参数的 SVC 估计器的性能,以确定哪个超参数选择最能预测我们的模拟数据。我们将使用 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 表示形式或信任 notebook。
在 GitHub 上,HTML 表示形式无法渲染,请尝试使用 nbviewer.org 加载此页面。
参数
estimator estimator: 估计器对象

假定该对象实现了 scikit-learn 估计器接口。
估计器要么需要提供 `score` 函数,
要么必须传入 `scoring` 参数。
SVC(random_state=0)
param_grid param_grid: 字典或字典列表

以参数名称(`str`)为键,以待尝试的参数设置列表为值的字典,或者此类字典的列表,在这种情况下将探索列表中每个字典所涵盖的网格。这使得能够搜索任意参数设置序列。
[{'kernel': ['linear']}, {'degree': [2, 3], 'kernel': ['poly']}, ...]
scoring scoring: str, 可调用对象, 列表, 元组或字典, 默认=None

用于评估交叉验证模型在测试集上性能的策略。

如果 `scoring` 代表单个分数,可以使用:

- 单个字符串(请参阅 :ref:`scoring_string_names`);
- 返回单个值的可调用对象(请参阅 :ref:`scoring_callable`);
- `None`,使用估计器的 :ref:`默认评估准则 <scoring_api_overview>`。

如果 `scoring` 代表多个分数,可以使用:

- 唯一字符串的列表或元组;
- 返回字典的可调用对象,其中键是指标名称,值是指标得分;
- 以指标名称为键、可调用对象为值的字典。

请参阅 :ref:`multimetric_grid_search` 以获取示例。
'roc_auc'
cv cv: int, 交叉验证生成器或可迭代对象, 默认=None

决定交叉验证分割策略。cv 的可能输入包括:

- None,使用默认的 5 折交叉验证,
- 整数,指定 `(Stratified)KFold` 中的折数,
- :term:`CV 分割器`,
- 产生 (train, test) 分割作为索引数组的可迭代对象。

对于整数/None 输入,如果估算器是分类器且 ``y`` 是二分类或多分类,则使用 :class:`StratifiedKFold`。在所有其他情况下,使用 :class:`KFold`。这些分割器在实例化时使用 `shuffle=False`,因此在各次调用中分割是相同的。

有关此处可以使用的各种交叉验证策略,请参考 :ref:`用户指南 <cross_validation>`。

.. versionchanged:: 0.22
如果为 None,``cv`` 默认值由 3 折改为 5 折。
RepeatedStrat...andom_state=0)
n_jobs n_jobs: int, 默认=None

并行运行的作业数。``None`` 表示 1,除非在 :obj:`joblib.parallel_backend` 上下文中。``-1`` 表示使用所有处理器。详情参见 :term:`术语表 <n_jobs>`。

.. versionchanged:: v0.20
`n_jobs` 默认值由 1 更改为 None
None
refit refit: bool, str, 或 callable, 默认=True

使用在整个数据集上找到的最佳参数重新拟合估计器。

对于多指标评估,这需要是一个字符串(str),表示在最后用于寻找最佳参数以重新拟合估计器的评分器(scorer)。

当选择最佳估计器时,除了最大分数外还有其他考量因素时,可以将 ``refit`` 设置为一个函数,该函数根据 ``cv_results_`` 返回所选的 ``best_index_``。在这种情况下,``best_estimator_`` 和 ``best_params_`` 将根据返回的 ``best_index_`` 进行设置,而 ``best_score_`` 属性将不可用。

重新拟合后的估计器可在 ``best_estimator_`` 属性中获取,并允许直接在此 ``GridSearchCV`` 实例上使用 ``predict``。

同样对于多指标评估,``best_index_``、``best_score_`` 和 ``best_params_`` 属性仅在设置了 ``refit`` 的情况下可用,并且它们都将相对于此特定评分器确定。

有关多指标评估的更多信息,请参阅 ``scoring`` 参数。

请参阅 :ref:`sphx_glr_auto_examples_model_selection_plot_grid_search_digits.py`
以了解如何通过 `refit` 使用 callable 设计自定义选择策略。

请参阅 :ref:`此示例
<sphx_glr_auto_examples_model_selection_plot_grid_search_refit_callable.py>`
了解如何使用 ``refit=callable`` 来平衡模型复杂性和交叉验证得分。

.. versionchanged:: 0.20
增加了对 callable 的支持。
True
verbose verbose: int, 默认=0

控制拟合期间打印信息的详细程度,值越高,日志越详细。

- 0 : 不打印任何消息;
- >=1 : 总拟合次数摘要;
- >=2 : 每个折叠和参数候选的计算时间;
- >=3 : 折叠索引和得分;
- >=10 : 参数候选索引以及每次拟合前的开始消息。
0
pre_dispatch pre_dispatch: int 或 str, 默认='2*n_jobs'

控制并行执行期间分发的作业数量。减少该数量有助于避免在分发的作业数量多于 CPU 所能处理的范围时发生内存消耗激增。此参数可以是:

- None,在这种情况下,所有作业会立即创建并衍生。对于轻量级且快速运行的作业使用此项,以避免由于按需衍生作业而导致的延迟;
- int,给出衍生的总作业的准确数量;
- str,给出作为 n_jobs 函数的表达式,如 '2*n_jobs'。
'2*n_jobs'
error_score error_score: 'raise' 或数值, 默认=np.nan

如果在估算器拟合过程中发生错误,要分配给得分的值。如果设置为 'raise',则会引发错误。如果给定了数值,则会发出 FitFailedWarning。此参数不影响重新拟合步骤,该步骤将始终引发错误。
nan
return_train_score return_train_score: bool, 默认=False

如果为 ``False``,``cv_results_`` 属性将不包含训练得分。计算训练得分用于深入了解不同参数设置如何影响过拟合/欠拟合的折中。然而,计算训练集上的得分可能会消耗大量计算资源,并且在选择能产生最佳泛化性能的参数时,并非严格必需。

.. versionadded:: 0.19

.. versionchanged:: 0.21
默认值从 ``True`` 更改为 ``False``
False
拟合属性
名称 类型 值
best_estimator_ best_estimator_: 估计器

由搜索选择的估计器,即在留出数据上得分最高(或指定时损失最小)的估计器。如果 `refit=False`,则不可用。

有关允许值的更多信息,请参阅 `refit` 参数。
SVC SVC(random_state=0)
best_index_ best_index_: int

对应于最佳候选参数设置的索引(`cv_results_` 数组中的)。

`search.cv_results_['params'][search.best_index_]` 处的字典给出了最佳模型的参数设置,该设置提供了最高的平均得分(`search.best_score_`)。

对于多指标评估,仅在指定了 `refit` 时才会存在。
int64 np.int64(3)
best_params_ best_params_: 字典

在留出数据上产生最佳结果的参数设置。

对于多指标评估,仅在指定了 `refit` 时才会存在。
dict {'kernel': 'rbf'}
best_score_ best_score_: float

最佳估计器的平均交叉验证分数

对于多指标评估,仅在指定了 ``refit`` 时存在。

如果 ``refit`` 是一个函数,则该属性不可用。
float64 0.94
classes_ classes_: 形状为 (n_classes,) 的 ndarray

类别标签。仅在指定了 ``refit`` 且底层估算器是分类器时才存在。
ndarray[int64](2,) [0,1]
cv_results_ cv_results_: numpy (masked) ndarrays 的字典

一个以列标题为键、各列为值的字典,可导入到 pandas ``DataFrame`` 中。

例如下表

+------------+-----------+------------+-----------------+---+---------+
|param_kernel|param_gamma|param_degree|split0_test_score|...|rank_t...|
+============+===========+============+=================+===+=========+
| 'poly' | -- | 2 | 0.80 |...| 2 |
+------------+-----------+------------+-----------------+---+---------+
| 'poly' | -- | 3 | 0.70 |...| 4 |
+------------+-----------+------------+-----------------+---+---------+
| 'rbf' | 0.1 | -- | 0.80 |...| 3 |
+------------+-----------+------------+-----------------+---+---------+
| 'rbf' | 0.2 | -- | 0.93 |...| 1 |
+------------+-----------+------------+-----------------+---+---------+

将由如下的 ``cv_results_`` 字典表示:::

{
'param_kernel': masked_array(data = ['poly', 'poly', 'rbf', 'rbf'],
mask = [False False False False]...)
'param_gamma': masked_array(data = [-- -- 0.1 0.2],
mask = [ True True False False]...),
'param_degree': masked_array(data = [2.0 3.0 -- --],
mask = [False False True True]...),
'split0_test_score' : [0.80, 0.70, 0.80, 0.93],
'split1_test_score' : [0.82, 0.50, 0.70, 0.78],
'mean_test_score' : [0.81, 0.60, 0.75, 0.85],
'std_test_score' : [0.01, 0.10, 0.05, 0.08],
'rank_test_score' : [2, 4, 3, 1],
'split0_train_score' : [0.80, 0.92, 0.70, 0.93],
'split1_train_score' : [0.82, 0.55, 0.70, 0.87],
'mean_train_score' : [0.81, 0.74, 0.70, 0.90],
'std_train_score' : [0.01, 0.19, 0.00, 0.03],
'mean_fit_time' : [0.73, 0.63, 0.43, 0.49],
'std_fit_time' : [0.01, 0.02, 0.01, 0.01],
'mean_score_time' : [0.01, 0.06, 0.04, 0.04],
'std_score_time' : [0.00, 0.00, 0.00, 0.01],
'params' : [{'kernel': 'poly', 'degree': 2}, ...],
}

关于 GridSearch 结果的可视化和解读示例,请参阅 :ref:`sphx_glr_auto_examples_model_selection_plot_grid_search_stats.py`。

注意

键 ``'params'`` 用于存储所有参数候选的参数设置字典列表。

``mean_fit_time``、``std_fit_time``、``mean_score_time`` 和 ``std_score_time`` 的单位均为秒。

对于多指标评估,所有评分器的分数可在 ``cv_results_`` 字典中找到,键名为以该评分器名称结尾的字符串(``'_<scorer_name>'``),而不是上述的 ``'_score'``。(如 'split0_test_precision', 'mean_train_precision' 等)
dict {'me...me': array([0., 0., 0., 0.]), 'me...me': array([0., 0., 0., 0.]), 'me...re': array([0.93, ..., 0.9 , 0.94]), 'pa...ee': masked_array(..._value=999999), ...}
multimetric_ multimetric_: bool

评分器是否计算多个度量指标。
bool False
n_features_in_ n_features_in_: int

在 :term:`fit` 期间见过的特征数量。仅在定义了 `best_estimator_`(更多详情参见 `refit` 参数文档)且该 `best_estimator_` 在拟合时公开了 `n_features_in_` 时才定义。

.. versionadded:: 0.24
int 2
n_splits_ n_splits_: int

交叉验证分割(折数/迭代次数)的数量。
int 100
refit_time_ refit_time_: float

在整个数据集上重新拟合最佳模型所用的秒数。

仅在 ``refit`` 不为 False 时存在。

.. versionadded:: 0.20
float 0.002359
scorer_ scorer_: 函数或字典

在留出数据上用于选择模型最佳参数的评分函数。

对于多指标评估,此属性包含经过验证的 ``scoring`` 字典,该字典将评分器键映射到评分器可调用对象。
_Scorer make_scorer(r...edict_proba'))
SVC(random_state=0)
参数
random_state random_state: int, RandomState 实例或 None, default=None

控制用于概率估计的数据洗牌的伪随机数生成。当 `probability` 为 False 时被忽略。传入 int 以在多次函数调用中获得可重复的输出。参见 :term:`术语表 <random_state>`。
0
C C: float, default=1.0

正则化参数。正则化的强度与 C 成反比。必须严格为正。惩罚项为平方 L2 惩罚。有关缩放正则化参数 C 的影响的直观可视化,请参阅 :ref:`sphx_glr_auto_examples_svm_plot_svm_scale_c.py`。
1.0
kernel kernel: {'linear', 'poly', 'rbf', 'sigmoid', 'precomputed'} 或可调用对象,default='rbf'

指定算法中使用的核类型。如果不提供,则使用 'rbf'。如果给定可调用对象,则用于从数据矩阵预计算核矩阵;该矩阵应为形状为 ``(n_samples, n_samples)`` 的数组。关于不同核类型的直观可视化,请参阅 :ref:`sphx_glr_auto_examples_svm_plot_svm_kernels.py`。
'rbf'
degree degree: int, default=3

多项式核函数 ('poly') 的次数。必须为非负数。所有其他核函数均忽略此参数。
3
gamma gamma: {'scale', 'auto'} 或 float, default='scale'

'rbf', 'poly' 和 'sigmoid' 的核系数。

- 如果传入 ``gamma='scale'``(默认值),则使用 1 / (n_features * X.var()) 作为 gamma 值,
- 如果为 'auto',则使用 1 / n_features
- 如果为 float,则必须为非负数。

.. versionchanged:: 0.22
``gamma`` 的默认值从 'auto' 更改为 'scale'。
'scale'
coef0 coef0: float, default=0.0

核函数中的独立项。仅在 'poly' 和 'sigmoid' 中有意义。
0.0
shrinking shrinking: bool, default=True

是否使用收缩(shrinking)启发式方法。请参阅 :ref:`用户指南 <shrinking_svm>`。
True
probability probability: bool, default=False

是否启用概率估计。必须在调用 `fit` 之前启用,这会减慢该方法的运行速度,因为它在内部使用了 5 折交叉验证,且 `predict_proba` 可能与 `predict` 不一致。阅读 :ref:`用户指南 <scores_probabilities>` 了解更多信息。

.. deprecated:: 1.9
`probability` 参数已弃用,并将在 1.11 中删除。请使用 `CalibratedClassifierCV(SVC(), ensemble=False)` 代替 `SVC(probability=True)`。
'deprecated'
tol tol: float, default=1e-3

停止准则的容差。
0.001
cache_size cache_size: float, default=200

指定核缓存的大小(以 MB 为单位)。
200
class_weight class_weight: dict 或 'balanced', default=None

将类 i 的参数 C 设置为 class_weight[i]*C(针对 SVC)。如果不提供,则假设所有类的权重为 1。
"balanced" 模式利用 y 的值自动调整权重,使其与输入数据中的类频率成反比,计算公式为 ``n_samples / (n_classes * np.bincount(y))``。
None
verbose verbose: bool, default=False

启用详细输出。请注意,此设置利用了 libsvm 中的每个进程运行时设置,如果启用,在多线程上下文中可能无法正常工作。
False
max_iter max_iter: int, default=-1

求解器内迭代的硬限制,-1 表示无限制。
-1
decision_function_shape decision_function_shape: {'ovo', 'ovr'}, default='ovr'

是否返回与其他分类器形状相同的形状为 (n_samples, n_classes) 的一对多 ('ovr') 决策函数,或者返回 libsvm 原生形状为 (n_samples, n_classes * (n_classes - 1) / 2) 的一对一 ('ovo') 决策函数。然而,请注意,在内部始终使用一对一 ('ovo') 作为训练模型的多分类策略;ovr 矩阵仅从 ovo 矩阵构造。该参数对于二分类被忽略。

.. versionchanged:: 0.19
decision_function_shape 默认为 'ovr'。

.. versionadded:: 0.17
建议使用 *decision_function_shape='ovr'*。

.. versionchanged:: 0.17
已弃用 *decision_function_shape='ovo' 和 None*。
'ovr'
break_ties break_ties: bool, default=False

如果为 true,``decision_function_shape='ovr'`` 且类别数 > 2,则 :term:`predict` 将根据 :term:`decision_function` 的置信度值打破平局;否则,将返回平局类别中的第一个类别。请注意,相比于简单的预测,打破平局会带来相对较高的计算成本。请参阅 :ref:`sphx_glr_auto_examples_svm_plot_svm_tie_breaking.py` 以获取其与 ``decision_function_shape='ovr'`` 一起使用的示例。

.. versionadded:: 0.22
False
拟合属性
名称 类型 值
class_weight_ class_weight_: 形状为 (n_classes,) 的 ndarray

每个类别的参数 C 的乘数。根据 ``class_weight`` 参数计算得出。
ndarray[float64](2,) [1.,1.]
classes_ classes_: 形状为 (n_classes,) 的 ndarray

类别标签。
ndarray[int64](2,) [0,1]
dual_coef_ dual_coef_: 形状为 (n_classes -1, n_SV) 的 ndarray 或稀疏数组/矩阵

决策函数中支持向量的对偶系数(参见 :ref:`sgd_mathematical_formulation`),乘以其目标值。
对于多分类,这是所有 1 对 1 分类器的系数。
多分类情况下系数的布局比较复杂。详细信息请参阅 :ref:`用户指南的多分类部分 <svm_multi_class>`。
如果 `X` 是稀疏的,则这些系数也将是稀疏的。
ndarray[float64](1, 48) [[-1. ,-0.09,-1. ,..., 1. , 1. , 0.19]]
fit_status_ fit_status_: int

0 表示拟合正确,1 表示其他情况(会引发警告)
int 0
intercept_ intercept_: 形状为 (n_classes * (n_classes - 1) / 2,) 的 ndarray

决策函数中的常量。
ndarray[float64](1,) [0.01]
n_features_in_ n_features_in_: int

在 :term:`fit` 期间看到的特征数量。

.. 新增版本:: 0.24
int 2
n_iter_ n_iter_: 形状为 (n_classes * (n_classes - 1) // 2,) 的 ndarray

优化程序拟合模型所运行的迭代次数。此属性的形状取决于被优化的模型数量,进而取决于类别数量。

.. versionadded:: 1.1
ndarray[int32](1,) [47]
n_support_ n_support_: 形状为 (n_classes,) 的 ndarray,dtype=int32

每个类别的支持向量数量。
ndarray[int32](2,) [24,24]
probA_ probA_: 形状为 (n_classes * (n_classes - 1) / 2) 的 ndarray

如果 `probability=True`,它对应于 Platt 缩放中学习到的参数,用于从决策值产生概率估计。
如果 `probability=False`,则为空数组。Platt 缩放使用逻辑函数。
ndarray[float64](0,) []
probB_ probB_: 形状为 (n_classes * (n_classes - 1) / 2) 的 ndarray

如果 `probability=True`,它对应于 Platt 缩放中学习到的参数。Platt 缩放使用逻辑函数
``1 / (1 + exp(decision_value * probA_ + probB_))``
其中 ``probA_`` 和 ``probB_`` 是从数据集 [2]_ 中学习得到的。有关多分类情况和训练过程的更多信息,请参阅 [1]_ 的第 8 节。

.. deprecated:: 1.9
属性 `probA_` 和 `probB_` 在 1.9 版本中已被弃用,并将在 1.11 版本中移除。
ndarray[float64](0,) []
shape_fit_ shape_fit_: 形状为 (n_dimensions_of_X,) 的整数元组

训练向量 ``X`` 的数组维度。
tuple (100, 2)
support_ support_: 形状为 (n_SV) 的 ndarray

支持向量的索引。
ndarray[int32](48,) [ 2, 6,20,...,89,93,97]
support_vectors_ support_vectors_: 形状为 (n_SV, n_features) 的 ndarray 或稀疏数组/矩阵

支持向量。如果内核已预计算,则为空数组。如果 `X` 是稀疏的,则这些向量也将是稀疏的。
ndarray[float64](48, 2) [[-0.27, 0.07], [-1.14, 1.21], [ 0.45, 0.06], ..., [ 1.36,-0.15], [ 1.26,-0.14], [ 0.52,-1.45]]


现在我们可以检查搜索结果,按其 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 检验的变体。我们将使用被证明能获得最高可重复性分数(衡量模型在评估同一数据集的不同随机分区时性能相似度)同时保持低假阳性和假阴性率的方法:使用 10 次重复 10 折交叉验证的 Nadeau 和 Bengio 校正 t 检验 [2] [3]。

此校正配对 t 检验计算公式为

\[t=\frac{\frac{1}{k \cdot r}\sum_{i=1}^{k}\sum_{j=1}^{r}x_{ij}} {\sqrt{(\frac{1}{k \cdot r}+\frac{n_{test}}{n_{train}})\hat{\sigma}^2}}\]

其中 \(k\) 是折数,\(r\) 是交叉验证中的重复次数,\(x\) 是模型性能的差异,\(n_{test}\) 是用于测试的样本数,\(n_{train}\) 是用于训练的样本数,\(\hat{\sigma}^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(next(iter(cv.split(X, y)))[0])
n_test = len(next(iter(cv.split(X, y)))[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 检验得出结论认为第一个模型显著优于第二个模型。

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

然而在后者情况下,频率派方法无法让我们得出第一个和第二个模型性能相等的结论。如果我们要做出这种断言,就需要使用贝叶斯方法。

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

我们可以使用贝叶斯估计来计算第一个模型优于第二个模型的概率。贝叶斯估计将输出一个分布,该分布跟随两个模型性能差异的均值 \(\mu\)。

为了获得后验分布,我们需要定义一个先验(建模我们在查看数据前对均值分布的信念),并将其与似然函数相乘(该函数计算在给定均值可能的取值下,观察到的差异有多大可能)。

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

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

\[St(\mu;n-1,\overline{x},(\frac{1}{n}+\frac{n_{test}}{n_{train}}) \hat{\sigma}^2)\]

其中 \(n\) 是样本总数,\(\overline{x}\) 代表分数的平均差异,\(n_{test}\) 是用于测试的样本数,\(n_{train}\) 是用于训练的样本数,\(\hat{\sigma}^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

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

请注意,我们得到的结果与频率派方法中的结果相似。鉴于我们对先验的选择,我们本质上是在进行相同的计算,但可以做出不同的断言。

实际等效区域 (ROPE)#

有时我们有兴趣确定模型性能相等的概率,其中“相等”是在实际意义上定义的。一种简单的做法 [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%(5% 的 alpha 值)?如果是,我们可以得出结论,两个模型在实际应用中是等效的。

贝叶斯估计方法还允许我们计算对差异估计的不确定性程度。这可以使用可信区间来计算。对于给定的概率,它们显示了估计量(在我们的例子中是性能的平均差异)可以取的数值范围。例如,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
模型_1 模型_2 t_统计量 p_值
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
模型_1 模型_2 t_统计量 p_值 更差_概率 更好_概率 ROPE_概率
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% 的概率如此。

与频率派方法得出的结论类似,所有模型都有 100% 的概率比 '2_poly' 表现更好,且没有模型与后者具有实际等效的性能。

核心要点#

  • 性能指标上的细微差异很容易仅仅是偶然造成的,而不是因为一个模型系统地预测得比另一个好。正如本示例所示,统计学可以告诉你这种情况的可能性。

  • 在统计比较 GridSearchCV 评估的两个模型性能时,有必要校正计算出的方差,因为模型的分数之间并非独立,可能导致方差被低估。

  • 使用(方差校正)配对 t 检验的频率派方法可以告诉我们一个模型的性能是否以高于随机性的确定程度优于另一个模型。

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

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

References

[1]

Dietterich, T. G. (1998). Approximate statistical tests for comparing supervised classification learning algorithms. Neural computation, 10(7).

[2]

Nadeau, C., & Bengio, Y. (2000). Inference for the generalization error. In Advances in neural information processing systems.

[3]

Bouckaert, R. R., & Frank, E. (2004). Evaluating the replicability of significance tests for comparing learning algorithms. In Pacific-Asia Conference on Knowledge Discovery and Data Mining.

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

Benavoli, A., Corani, G., Demšar, J., & Zaffalon, M. (2017). Time for a change: a tutorial for comparing multiple classifiers through Bayesian analysis. The Journal of Machine Learning Research, 18(1). 查看该论文附带的 Python 库 此处。

[5]

Diebold, F.X. & Mariano R.S. (1995). Comparing predictive accuracy Journal of Business & economic statistics, 20(1), 134-144.

脚本运行总耗时: (0 分钟 2.407 秒)

Launch binder
Launch JupyterLite

下载 Jupyter 笔记本: plot_grid_search_stats.ipynb

下载 Python 源代码: plot_grid_search_stats.py

下载 压缩包: plot_grid_search_stats.zip

相关示例

通过排列测试分类得分的显著性

通过排列测试分类得分的显著性

分类器校准比较

分类器校准比较

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

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

RBF SVM 参数

RBF SVM 参数

由 Sphinx-Gallery 生成的图库

上一页

文本特征提取和评估的示例流水线

下一页

Successive Halving 迭代

在本页
  • 比较两个模型:频率派方法
  • 比较两个模型:贝叶斯方法
    • 实际等效区域
  • 所有模型的成对比较:频率派方法
  • 所有模型的成对比较:贝叶斯方法
  • 核心要点
下载源代码
下载 Jupyter notebook
下载压缩包
Launch JupyterLite
Launch binder

scikit-learn 受到 Probabl 和其他机构的资金支持。

企业级解决方案与服务

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