Skip to main content
Ctrl+K
scikit-learn homepage
  • 安装
  • 用户指南
  • API
  • 示例
  • 社区
    • 入门
    • 解除历史记录
    • 术语表
    • 发展
    • FAQ
    • 支持
    • 相关项目
    • 路线图
    • 治理
    • 关于我们
  • GitHub
  • 安装
  • 用户指南
  • API
  • 示例
  • 社区
    • 入门
    • 解除历史记录
    • 术语表
    • 发展
    • FAQ
    • 支持
    • 相关项目
    • 路线图
    • 治理
    • 关于我们
  • GitHub

Section Navigation

  • 发布亮点
    • scikit-learn 1.6的发布亮点
    • scikit-learn 1.5的发布亮点
    • scikit-learn 1.4的发布亮点
    • scikit-learn 1.3的发布亮点
    • scikit-learn 1.1的发布亮点
    • scikit-learn 1.0的发布亮点
    • scikit-learn 0.24发布亮点
    • scikit-learn 0.23的发布亮点
  • 双聚类
    • 光谱双集群算法的演示
    • 光谱协同聚集算法的演示
    • 使用谱协同集群算法对文档进行二集群
  • 校准
    • 分类器校准的比较
    • 概率校准曲线
    • 分类器的概率校准
  • 分类
    • 分类器比较
    • 具有协方差椭圆体的线性和二次鉴别分析
    • 用于分类的正态、Ledoit-Wolf和OAS线性鉴别分析
    • 识别手写数字
  • 聚类
    • 手写数字数据上的K-Means集群演示
    • 硬币图像上的结构化Ward分层集群演示
    • 均值漂移集群算法的演示
    • 集群绩效评估中的机会调整
    • 有结构和不有结构的集聚
    • 具有不同指标的聚集性集群
    • K-Means++初始化的示例
    • 二分K均值和常规K均值性能比较
    • 比较BIRCH和MiniBatchKMeans
    • 在玩具数据集上比较不同的聚类算法
    • 在玩具数据集上比较不同的分层链接方法
    • K-Means和MiniBatchKMeans集群算法的比较
    • DBSCAN集群算法演示
    • HDSCAN集群算法演示
    • OPTICS分簇算法演示
    • 亲和力传播分簇算法演示
    • k均值假设的证明
    • k均值初始化影响的实证评估
    • 特征聚集
    • 特征聚集与单变量选择
    • 分层集群:结构化与非结构化病房
    • 归纳集群
    • 在线学习面部部分词典
    • 图分层聚集树图
    • 按地区划分希腊硬币的图片
    • 在KMeans聚类中使用轮廓分析选择聚类数
    • 用于图像分割的光谱集群
    • 2D数字嵌入上的各种聚集性聚集
    • 载体量化示例
  • 协方差估计
    • Ledoit-Wolf与OAS估计
    • 稳健协方差估计和Mahalanobis距离相关性
    • 稳健与经验协方差估计
    • 收缩协方差估计:LedoitWolf vs OAS和最大似然
    • 稀疏逆协方差估计
  • 交叉分解
    • 比较交叉分解方法
    • 主成分回归与偏最小平方回归
  • 数据集示例
    • 绘制随机生成的多标签数据集
  • 决策树
    • 决策树回归
    • 绘制在虹膜数据集上训练的决策树的决策面
    • 具有成本复杂性修剪的后修剪决策树
    • 了解决策树结构
  • 分解
    • 使用FastICA的盲源分离
    • Iris数据集LDA和PCA 2D投影的比较
    • Faces数据集分解
    • 因子分析(旋转)以可视化模式
    • 2D点云上的FastICA
    • 使用字典学习的图像去噪
    • 增量PCA
    • 核PCA
    • 使用概率PCA和因子分析(FA)进行模型选择
    • Iris数据集的主成分分析(PCA)
    • 使用预先计算的字典进行稀疏编码
  • 开发估算器
    • __sklearn_is_fitted__ 作为开发人员API
  • 集成方法
    • 梯度提升中的分类特征支持
    • 使用堆叠组合预测因子
    • 比较随机森林和柱状图梯度增强模型
    • 比较随机森林和多输出Meta估计量
    • 使用AdaBoost进行决策树回归
    • Gradient Boosting中的提前停止
    • 树木森林的重要性
    • 使用树木集合的特征转换
    • 梯度增强树的梯度中的功能
    • 梯度提升袋外估计
    • 梯度增强回归
    • 梯度提升正规化
    • 使用完全随机树哈希特征转换
    • 隔离森林示例
    • 单调约束
    • 多类AdaBoosted决策树
    • 随机森林的OOB错误
    • 绘制个人和投票回归预测图
    • 在虹膜数据集中绘制树木集合的决策面
    • 梯度Boosting回归的预测区间
    • 单一估计量与装袋:偏差方差分解
    • 两级AdaBoost
    • 可视化VotingClassifier的概率预测
  • 基于现实世界数据集的示例
    • 压缩感知:使用L1先验进行断层扫描重建(Lasso)
    • 使用特征脸和SVM的人脸识别示例
    • 基于核主成分分析的图像去噪
    • 时间序列预测的滞后特征
    • 模型复杂性影响
    • 真实数据集上的离群值检测
    • 预测延迟
    • 物种分布建模
    • 与时间相关的特征工程
    • 非负矩阵分解和潜在Dirichlet分配的主题提取
    • 股票市场结构可视化
    • 维基百科主特征量
  • 特征选择
    • F检验与互信息的比较
    • 基于模型的顺序特征选择
    • 流水线ANOVA SVM
    • 递归特征消除
    • 单变量特征选择
  • 冻结的估计者
    • 例子利用 FrozenEstimator
  • 高斯混合模型
    • 变异Bayesian高斯混合物的浓度先验型分析
    • 高斯混合物的密度估计
    • GMM检查方法
    • GMM协方差
    • 高斯混合模型椭圆体
    • 高斯混合模型选择
    • 高斯混合模型顺曲线
  • 机器学习的高斯过程
    • 高斯过程回归(GPT)估计数据噪音水平的能力
    • 核岭回归与高斯过程回归的比较
    • 使用高斯过程回归(GPT)预测Mona Loa数据集的二氧化碳水平
    • 高斯过程回归:基本入门示例
    • 虹膜数据集上的高斯过程分类(GSK)
    • 离散数据结构上的高斯过程
    • 异或数据集上的高斯过程分类(GSK)插图
    • 不同核的先验和后验高斯过程的说明
    • 高斯过程分类(GSK)的等概率线
    • 利用高斯过程分类(GSK)进行概率预测
  • 广义线性模型
    • 比较线性Bayesian回归量
    • 利用Bayesian Ridge回归进行曲线匹配
    • 多项和一对二回归的决策边界
    • 随机梯度下降的早停止
    • 使用预先计算的格拉姆矩阵和加权样本来匹配弹性网络
    • HuberRegressor与Ridge在具有强异常值的数据集上
    • 使用多任务Lasso进行联合特征选择
    • 逻辑回归中的L1罚分和稀疏性
    • 基于L1的稀疏信号模型
    • 通过信息标准选择Lasso模型
    • Lasso型号选择:AIC-BIC /交叉验证
    • 密集和稀疏数据上的套索
    • Lasso、Lasso-LARS和Elastic Net路径
    • 逻辑函数
    • 使用多项逻辑+ L1的MNIST分类
    • 20个新群体的多类稀疏逻辑回归
    • 非负最小平方
    • 使用随机梯度下降的一类支持者与一类支持者
    • 普通最小二乘和岭回归
    • 正交匹配追踪
    • 绘制岭系数作为正规化的函数
    • 在iris数据集上绘制多类新元
    • 多项和样条插值
    • 分位数回归
    • L1-逻辑回归的正规化路径
    • 作为L2正则化函数的脊系数
    • 鲁棒线性估计量匹配
    • 使用RASAC的鲁棒线性模型估计
    • 新元:分离超平面的最大裕度
    • 新元:处罚
    • 新元:加权样本
    • 新元:凸损失函数
    • Theil-Sen回归
  • 检查
    • 线性模型系数解释中的常见陷阱
    • 机器学习无法推断因果效应
    • 排列重要性与随机森林特征重要性(Millennium)
    • 具有多重共线或相关特征的排列重要性
  • 核近似
    • 具有多项核逼近的可扩展学习
  • 流形学习
    • 多种学习方法的比较
    • 分割球面上的流形学习方法
    • 手写数字的流形学习:局部线性嵌入,Isomap...
    • 多维标度
    • 瑞士滚动和瑞士洞减少
    • t-SNE:各种困惑度值对形状的影响
  • 杂项
    • 部分相关的高级绘图
    • 比较玩具数据集异常值检测的异常检测算法
    • 核岭回归与SVR的比较
    • 管道
    • NPS估计器和复杂管道
    • 基于RBS核的显式特征图逼近
    • 使用多输出估计器完成面
    • 介绍 set_output API
    • 保序回归
    • 元数据路由
    • 多标签分类
    • 随机投影嵌入的Johnson-Lindenstrauss界
    • 具有显示对象的可视化
  • 缺失值插补
    • 在构建估计器之前输入缺失值
    • 使用IterativeImputer的变体输入缺失值
  • 模型选择
    • 平衡模型复杂性和交叉验证分数
    • 比较随机搜索和网格搜索用于超参数估计
    • 网格搜索和连续减半的比较
    • 混淆矩阵
    • 具有交叉验证的网格搜索自定义改装策略
    • 基于cross_val_score和GridSearchCV的多度量评估演示
    • 模型正规化对训练和测试误差的影响
    • 嵌套与非嵌套交叉验证
    • 绘制交叉验证预测
    • 绘制学习曲线并检查模型的可扩展性
    • 事后调整决策函数的截止点
    • pr曲线
    • 具有交叉验证的接收器工作特性(ROC)
    • 用于文本特征提取和评估的样本管道
    • 使用网格搜索进行模型统计比较
    • 连续减半迭代
    • 用排列测试分类分数的重要性
    • 不足与过度贴合
    • 在scikit-learn中可视化交叉验证行为
  • 多类方法
    • 多类训练元估计器概述
  • 多输出方法
    • 使用分类器链的多标签分类
  • 最近邻居
    • TSNE的大约最近邻居
    • 缓存最近的邻居
    • 比较使用和不使用邻居成分分析的最近邻居
    • 利用邻居成分分析降低维度
    • 物种分布的核密度估计
    • 核密度估计
    • 最近的重心分类
    • 最近邻分类
    • 最近邻回归
    • 邻里要素分析插图
    • 利用本地异常值因子(LOF)进行新颖性检测
    • 使用局部离群因子(LOF)进行离群点检测
    • 简单的1D核密度估计
  • 神经网络
    • 比较MLP分类器的随机学习策略
    • 数字分类的受限制Boltzmann Machine功能
    • 多层感知器中的变化规则化
    • MNIST上MLP权重的可视化
  • 管道和复合估计量
    • 具有异类数据源的列Transformer
    • 混合类型的列Transformer
    • 级联多种特征提取方法
    • 回归模型中目标转换的效果
    • 流水线:链接PCA和逻辑回归
    • 使用Pipeline和GridSearchCV选择降维
  • 预处理
    • 比较不同缩放器对数据的影响与离群值
    • 比较目标编码器与其他编码器
    • 特征缩放的重要性
    • 将数据映射到正态分布
    • 目标编码器的内部交叉拟合
  • 半监督分类
    • Iris数据集上半监督分类器与支持机的决策边界
    • 不同阈值对自我训练的影响
    • 标签传播圈:学习复杂结构
    • 标签传播数字:主动学习
    • 标签传播数字:展示性能
    • 文本数据集的半监督分类
  • 支持向量机
    • 带非线性核(RBS)的一类支持者
    • 具有不同支持机核的地块分类边界
    • 在虹膜数据集中绘制不同的支持者分类器
    • 在LinearSRC中绘制支持载体
    • RBF SVM参数
    • 支持机边缘示例
    • SV打破平局示例
    • 具有自定义内核的支持者
    • SVM-Anova:具有单变量特征选择的支持者
    • SV:最大裕度分离超平面
    • 支持者:分离不平衡类别的超平面
    • 支持者:加权样本
    • 缩放SVCs的正规化参数
    • 使用线性和非线性核的支持量回归(SVR)
  • 使用文本文档
    • 使用稀疏特征对文本文档进行分类
    • 基于k-means的文本聚类
    • 收件箱Hasher和DictVectorizer比较
  • 示例
  • 模型选择
  • 使用网格搜索进行模型统计比较

备注

Go to the end 下载完整的示例代码。或者通过浏览器中的MysterLite或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

我们将比较 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')
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with 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' .两个估计器均为a 'poly' 内核的性能更差,使用二次方程的内核的性能比所有其他模型低得多。

通常,分析就在这里结束,但故事的一半却不见了。的输出 GridSearchCV 不提供有关模型之间差异的确定性的信息。我们不知道这些是否是 statistically 显著为了评估这一点,我们需要进行统计测试。具体来说,为了比较两个模型的性能,我们应该从统计上比较它们的UC分数。每个模型有100个样本(AUC评分),因为我们重复了10次10次10次交叉验证。

然而,模型的分数并不独立:所有模型都在 same 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].

针对这些情况开发了几种方差修正统计测试。在这个例子中,我们将展示如何在两个不同的统计框架下实现其中之一(所谓的纳多和Bengio的修正t检验):频率论和Bayesian。

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

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

为了使用频率论方法回答这个问题,我们可以运行配对t检验并计算p值。这在预测文献中也被称为迪博尔德-马里亚诺测试 [5]. 已经开发了此类t检验的许多变体来解决上一节描述的“样本的非独立性问题”。我们将使用被证明可以获得最高可复制性分数的分数(在同一数据集的不同随机分区上评估模型时,评估模型的性能的相似程度),同时保持较低的假阳性和假阴性率:Nadeau和Bengio的修正t检验 [2] 使用10次重复10倍交叉验证 [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和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 ,我们观察到未经修正的t检验得出的结论是,第一个模型明显优于第二个模型。

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

然而,在后一种情况下,频率论方法并不能让我们得出第一和第二模型具有等效性能的结论。如果我们想做出这一断言,我们需要使用Bayesian方法。

比较两个模型:Bayesian方法#

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

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

Bayesian估计可以以多种形式进行来回答我们的问题,但在这个例子中,我们将实现Benavoli及其同事建议的方法 [4].

使用封闭形式的公式定义后验的一种方法是选择似然函数的先验共乘。贝纳沃利和同事 [4] 表明,当比较两个分类器的性能时,我们可以将先验建模为与正态似然性相结合的正态-伽玛分布(均值和方差均未知),从而将后验表示为正态分布。将方差从这个正态后验边缘化,我们可以将均值参数的后验定义为Student 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\) 代表观察到的差异的方差。

请注意,我们在贝叶斯方法中也使用了纳多和本吉奥的校正方差。

让我们计算并绘制后验:

# 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%(阿尔法值为5%)? 在这种情况下,我们可以得出结论,两种模型实际上是等效的。

Bayesian估计方法还允许我们计算我们对差异估计的不确定性有多大。这可以使用可信的间隔来计算。对于给定的概率,它们显示了估计数量(在我们的情况下是性能的平均差异)可以采用的值范围。例如,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
lower value upper value
interval
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 .在这种情况下,我们将多次运行统计测试,这将导致 multiple comparisons problem .

有很多可能的方法可以解决这个问题,但标准方法是应用 Bonferroni correction . 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' .

所有模型的成对比较:Bayesian方法#

当使用Bayesian估计来比较多个模型时,我们不需要纠正多次比较(原因请参阅 [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


使用Bayesian方法,我们可以计算一个模型表现得更好、更差或实际上与另一个模型相当的概率。

结果表明,该模型排名第一 GridSearchCV 'rbf' ,大约有6.8%的机会比 'linear' ,比 '3_poly' . 'rbf' 和 'linear' 实际等效的可能性为43%,而 'rbf' 和 '3_poly' 有10%的可能性。

与使用频率论方法获得的结论类似,所有模型都有100%的可能性优于 '2_poly' ,并且没有一个具有与后者几乎相当的性能。

带回家的消息#

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

  • 当对GridSearchCV中评估的两个模型的性能进行统计比较时,有必要纠正计算出的方差,因为模型的分数并不相互独立,因此可能会被低估。

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

  • 贝叶斯方法可以提供一个模型比另一个模型更好、更差或实际等同的概率。它还可以告诉我们,我们有多大的信心知道我们的模型的真正差异落在一定的值范围内。

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

引用

[1]

迪特里希,T. G.(1998)。 Approximate statistical tests for comparing supervised classification learning algorithms .神经计算,10(7)。

[2]

纳多角,& Bengio,Y.(2000)。 Inference for the generalization error .神经信息处理系统的进展。

[3]

布卡特河R.,& Frank,E.(2004)。 Evaluating the replicability of significance tests for comparing learning algorithms .太平洋亚洲知识发现和数据挖掘会议。

[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 .《机器学习研究杂志》,18(1)。请参阅本文附带的Python库 here .

[5]

迪博尔德,FX &马里亚诺RS.(1995)。 Comparing predictive accuracy Journal of Business & Economic Statistics,20(1),134-144.

Total running time of the script: (0分1.271秒)

发布手册
推出FriendyterLite

Download Jupyter notebook: plot_grid_search_stats.ipynb

Download Python source code: plot_grid_search_stats.py

Download zipped: plot_grid_search_stats.zip

相关实例

用排列测试分类分数的重要性

Test with permutations the significance of a classification score

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

Common pitfalls in the interpretation of coefficients of linear models

分类器校准的比较

Comparison of Calibration of Classifiers

用于文本特征提取和评估的样本管道

Sample pipeline for text feature extraction and evaluation

Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io> _

上一页

用于文本特征提取和评估的样本管道

下一页

连续减半迭代

On this page
  • 比较两种模型:频率论方法
  • 比较两个模型:Bayesian方法
    • 实践等效领域
  • 所有模型的成对比较:频率论方法
  • 所有模型的成对比较:Bayesian方法
  • 带回家的消息
Download source code
Download Jupyter notebook
Download zipped
推出FriendyterLite
发布手册

© Copyright 2007 - 2025, scikit-learn developers (BSD License).