3.4. 指标和评分:量化预测质量#

3.4.1. 我应该使用哪个评分函数?#

在我们仔细研究许多分数和评估指标的细节之前,我们想根据统计决策理论,对监督学习评分函数的选择提供一些指导,参见[Gneiting2009]

  • 我应该使用哪个评分函数?

  • 哪个评分函数适合我的任务?

简而言之,如果评分函数已给出,例如在 Kaggle 竞赛或业务环境中,则使用该函数。如果您可以自由选择,则首先要考虑预测的最终目标和应用。区分两个步骤是有用的

  • 预测

  • 决策

预测:通常,响应变量\(Y\)是一个随机变量,这意味着没有关于特征\(X\)确定性函数\(Y = g(X)\)。相反,存在\(Y\)的概率分布\(F\)。可以目标预测整个分布,称为概率预测,或者——更侧重于 scikit-learn——通过选择该分布\(F\)的属性或泛函来发出点预测(或点预测)。典型的例子是响应变量\(Y\)的均值(期望值)、中位数或分位数(以\(X\)为条件)。

一旦确定这一点,请使用该(目标)泛函的严格一致评分函数,参见[Gneiting2009]。这意味着使用与测量预测y_pred和使用\(Y\)的观测值对目标泛函的真实值的距离,即y_true,一致的评分函数。对于分类严格正确的评分规则,参见评分规则的维基百科词条[Gneiting2007],与严格一致的评分函数一致。下面的表格提供了示例。可以说,一致的评分函数充当诚实药剂,因为它保证“说真话……在期望中是一种最佳策略” [Gneiting2014]

一旦选择了严格一致的评分函数,最好将其用于以下两方面:作为模型训练的损失函数以及模型评估和模型比较中的指标/分数。

请注意,对于回归器,预测是使用predict完成的,而对于分类器,通常是predict_proba

决策制定:最常见的决策是基于二元分类任务完成的,其中predict_proba的结果会被转化为单个结果,例如,根据预测的降雨概率来决定采取何种行动(是否采取携带雨伞等缓解措施)。对于分类器而言,这就是predict返回的结果。另见调整类预测的决策阈值。许多评分函数可以衡量此类决策的不同方面,大多数评分函数都基于或衍生自metrics.confusion_matrix

严格一致的评分函数列表:这里列出了一些在实践中与相关的统计函数和对应的严格一致的评分函数。需要注意的是,此列表并不完整,还有更多此类函数。有关如何选择特定函数的更多标准,请参见[Fissler2022]

函数

评分或损失函数

响应 y

预测值

分类

均值

Brier 分数 1

多类别

predict_proba

均值

对数损失

多类别

predict_proba

众数

零一损失 2

多类别

predict,类别型

回归

均值

平方误差 3

所有实数

predict,所有实数

均值

泊松偏差

非负数

predict,严格正数

均值

伽马偏差

严格正数

predict,严格正数

均值

Tweedie 偏差

取决于 power

predict,取决于 power

中位数

绝对误差

所有实数

predict,所有实数

分位数

铰链损失

所有实数

predict,所有实数

众数

不存在一致的函数

实数

1 在分类情况下,Brier 分数只是平方误差的另一种名称。

2 零一损失仅对众数是一致的,但不是严格一致的。零一损失等效于 1 减去准确率分数,这意味着它给出不同的分数值,但排名相同。

3 R² 给出的排名与平方误差相同。

虚构示例:让我们使上述论点更切实可行。考虑网络可靠性工程中的一个设置,例如维护稳定的互联网或 Wi-Fi 连接。作为网络提供商,您可以访问包含网络负载随时间变化以及许多有趣特征的网络连接日志条目数据集。您的目标是提高连接的可靠性。事实上,您向客户承诺,在至少 99% 的日子里,连接中断不超过 1 分钟。因此,您感兴趣的是预测 99% 分位数(每天最长的连接中断持续时间),以便提前知道何时增加带宽并从而满足客户的需求。因此,*目标函数*是 99% 分位数。从上表中,您选择铰链损失作为评分函数(足够公平,鉴于此选择不多),用于模型训练(例如 HistGradientBoostingRegressor(loss="quantile", quantile=0.99))以及模型评估(mean_pinball_loss(..., alpha=0.99) - 我们为不同的参数名称道歉,quantilealpha)无论是在网格搜索中查找超参数还是在与其他模型(如 QuantileRegressor(quantile=0.99))进行比较时。

参考文献

[Gneiting2007]

T. Gneiting 和 A. E. Raftery。 严格正确的评分规则、预测和估计 载于:《美国统计协会杂志》102 (2007),第 359-378 页。pdf链接

[Gneiting2009] (1,2)

T. Gneiting。 制定和评估点预测 《美国统计协会杂志》106 (2009): 746 - 762。

[Gneiting2014]

T. Gneiting 和 M. Katzfuss。 概率预测。载于:《统计及其应用年度评论》1.1 (2014),第 125-151 页。

3.4.2. 评分 API 概述#

有 3 个不同的 API 用于评估模型预测的质量

最后,虚拟估计器 可用于获取随机预测的这些指标的基线值。

另请参阅

对于样本之间的“成对”指标(而非估计器或预测),请参阅成对指标、亲和力和内核部分。

3.4.3. scoring参数:定义模型评估规则#

内部使用交叉验证的模型选择和评估工具(例如model_selection.GridSearchCVmodel_selection.validation_curvelinear_model.LogisticRegressionCV)采用scoring参数来控制它们应用于所评估估计器的指标。

它们可以通过多种方式指定

  • None:使用估计器的默认评估标准(即,在估计器的score方法中使用的指标)。

  • 字符串名称:常用指标可以通过字符串名称传递。

  • 可调用对象:更复杂的指标可以通过自定义指标可调用对象(例如,函数)传递。

有些工具也接受多个指标评估。有关详细信息,请参阅使用多个指标评估

3.4.3.1. 字符串名称评分器#

对于最常见的用例,您可以通过字符串名称使用scoring参数指定评分器对象;下表显示所有可能的值。所有评分器对象都遵循以下约定:**返回值越高越好**。因此,测量模型与数据之间距离的指标(例如metrics.mean_squared_error)可用作“neg_mean_squared_error”,它返回指标的负值。

评分字符串名称

函数

注释

分类

‘accuracy’

metrics.accuracy_score

‘balanced_accuracy’

metrics.balanced_accuracy_score

‘top_k_accuracy’

metrics.top_k_accuracy_score

‘average_precision’

metrics.average_precision_score

‘neg_brier_score’

metrics.brier_score_loss

‘f1’

metrics.f1_score

用于二元目标

‘f1_micro’

metrics.f1_score

微平均

‘f1_macro’

metrics.f1_score

宏平均

‘f1_weighted’

metrics.f1_score

加权平均

‘f1_samples’

metrics.f1_score

按多标签样本

‘neg_log_loss’

metrics.log_loss

需要predict_proba支持

‘precision’ 等

metrics.precision_score

后缀与“f1”相同

‘recall’ 等

metrics.recall_score

后缀与“f1”相同

‘jaccard’ 等

metrics.jaccard_score

后缀与“f1”相同

‘roc_auc’

metrics.roc_auc_score

‘roc_auc_ovr’

metrics.roc_auc_score

‘roc_auc_ovo’

metrics.roc_auc_score

‘roc_auc_ovr_weighted’

metrics.roc_auc_score

‘roc_auc_ovo_weighted’

metrics.roc_auc_score

‘d2_log_loss_score’

metrics.d2_log_loss_score

聚类

‘adjusted_mutual_info_score’

metrics.adjusted_mutual_info_score

‘adjusted_rand_score’

metrics.adjusted_rand_score

‘completeness_score’

metrics.completeness_score

‘fowlkes_mallows_score’

metrics.fowlkes_mallows_score

‘homogeneity_score’

metrics.homogeneity_score

‘mutual_info_score’

metrics.mutual_info_score

‘normalized_mutual_info_score’

metrics.normalized_mutual_info_score

‘rand_score’

metrics.rand_score

‘v_measure_score’

metrics.v_measure_score

回归

‘explained_variance’

metrics.explained_variance_score

‘neg_max_error’

metrics.max_error

‘neg_mean_absolute_error’

metrics.mean_absolute_error

‘neg_mean_squared_error’

metrics.mean_squared_error

‘neg_root_mean_squared_error’

metrics.root_mean_squared_error

‘neg_mean_squared_log_error’

metrics.mean_squared_log_error

‘neg_root_mean_squared_log_error’

metrics.root_mean_squared_log_error

‘neg_median_absolute_error’

metrics.median_absolute_error

‘r2’

metrics.r2_score

‘neg_mean_poisson_deviance’

metrics.mean_poisson_deviance

‘neg_mean_gamma_deviance’

metrics.mean_gamma_deviance

‘neg_mean_absolute_percentage_error’

metrics.mean_absolute_percentage_error

‘d2_absolute_error_score’

metrics.d2_absolute_error_score

使用示例

>>> from sklearn import svm, datasets
>>> from sklearn.model_selection import cross_val_score
>>> X, y = datasets.load_iris(return_X_y=True)
>>> clf = svm.SVC(random_state=0)
>>> cross_val_score(clf, X, y, cv=5, scoring='recall_macro')
array([0.96..., 0.96..., 0.96..., 0.93..., 1.        ])

注意

如果传递了错误的评分名称,则会引发InvalidParameterError。您可以通过调用get_scorer_names来检索所有可用评分器的名称。

3.4.3.2. 可调用评分器#

对于更复杂的用例和更大的灵活性,您可以将可调用对象传递给scoring参数。这可以通过以下方式完成:

3.4.3.2.1. 通过make_scorer调整预定义指标#

以下指标函数未实现为命名评分器,有时是因为它们需要其他参数,例如fbeta_score。它们不能传递给scoring参数;相反,它们的调用对象需要与用户可设置参数的值一起传递给make_scorer

函数

参数

示例用法

分类

metrics.fbeta_score

beta

make_scorer(fbeta_score, beta=2)

回归

metrics.mean_tweedie_deviance

power

make_scorer(mean_tweedie_deviance, power=1.5)

metrics.mean_pinball_loss

alpha

make_scorer(mean_pinball_loss, alpha=0.95)

metrics.d2_tweedie_score

power

make_scorer(d2_tweedie_score, power=1.5)

metrics.d2_pinball_score

alpha

make_scorer(d2_pinball_score, alpha=0.95)

一个典型的用例是用库中现有的度量函数及其参数的非默认值来包装它,例如fbeta_score函数的beta参数。

>>> from sklearn.metrics import fbeta_score, make_scorer
>>> ftwo_scorer = make_scorer(fbeta_score, beta=2)
>>> from sklearn.model_selection import GridSearchCV
>>> from sklearn.svm import LinearSVC
>>> grid = GridSearchCV(LinearSVC(), param_grid={'C': [1, 10]},
...                     scoring=ftwo_scorer, cv=5)

模块sklearn.metrics还提供了一组简单的函数,用于根据真实值和预测值来衡量预测误差。

  • _score结尾的函数返回要最大化的值,值越高越好。

  • _error_loss_deviance结尾的函数返回要最小化的值,值越低越好。当使用make_scorer将其转换为评分器对象时,请将greater_is_better参数设置为False(默认为True;参见下面的参数说明)。

3.4.3.2.2. 创建自定义评分器对象#

您可以使用make_scorer创建您自己的自定义评分器对象,或者为了获得最大的灵活性,可以从头开始创建。详情请见下文。

使用make_scorer创建自定义评分器对象#

您可以使用make_scorer从简单的python函数构建一个完全自定义的评分器对象,它可以接收多个参数。

  • 您想要使用的python函数(如下例中的my_custom_loss_func)。

  • python函数是否返回分数(greater_is_better=True,默认值)还是损失(greater_is_better=False)。如果是损失,则python函数的输出将被评分器对象取反,符合交叉验证的约定,即评分器为更好的模型返回更高的值。

  • 仅限于分类指标:您提供的python函数是否需要连续的决策确定性。如果评分函数只接受概率估计(例如metrics.log_loss),则需要设置参数response_method="predict_proba"。有些评分函数不一定需要概率估计,而是需要非阈值决策值(例如metrics.roc_auc_score)。在这种情况下,您可以提供一个列表(例如,response_method=["decision_function", "predict_proba"]),评分器将按列表中给定的顺序使用第一个可用方法来计算分数。

  • 评分函数的任何其他参数,例如betalabels

以下是如何构建自定义评分器以及使用greater_is_better参数的示例。

>>> import numpy as np
>>> def my_custom_loss_func(y_true, y_pred):
...     diff = np.abs(y_true - y_pred).max()
...     return np.log1p(diff)
...
>>> # score will negate the return value of my_custom_loss_func,
>>> # which will be np.log(2), 0.693, given the values for X
>>> # and y defined below.
>>> score = make_scorer(my_custom_loss_func, greater_is_better=False)
>>> X = [[1], [1]]
>>> y = [0, 1]
>>> from sklearn.dummy import DummyClassifier
>>> clf = DummyClassifier(strategy='most_frequent', random_state=0)
>>> clf = clf.fit(X, y)
>>> my_custom_loss_func(y, clf.predict(X))
0.69...
>>> score(clf, X, y)
-0.69...
从头开始创建自定义评分器对象#

您可以通过从头开始构建自己的评分对象,而无需使用make_scorer工厂,来生成更灵活的模型评分器。

为了使一个可调用对象成为评分器,它需要满足以下两条规则指定的协议。

  • 它可以用参数(estimator, X, y)调用,其中estimator是要评估的模型,X是验证数据,yX的真实目标(在监督情况下)或None(在无监督情况下)。

  • 它返回一个浮点数,该浮点数量化了estimatorX上的预测质量,参考y。同样,按照惯例,数字越大越好,因此如果您的评分器返回损失,则该值应取反。

  • 高级:如果需要传递额外的元数据,它应该公开一个名为 get_metadata_routing 的方法来返回请求的元数据。用户应该能够通过 set_score_request 方法设置请求的元数据。更多细节请参考 用户指南开发者指南

在 n_jobs > 1 的函数中使用自定义评分器#

虽然在调用函数旁边定义自定义评分函数应该可以与默认的 joblib 后端 (loky) 一起开箱即用,但从另一个模块导入它将是一种更强大的方法,并且可以独立于 joblib 后端工作。

例如,要在下面的示例中使用大于 1 的 n_jobscustom_scoring_function 函数保存在用户创建的模块 (custom_scorer_module.py) 中并被导入。

>>> from custom_scorer_module import custom_scoring_function 
>>> cross_val_score(model,
...  X_train,
...  y_train,
...  scoring=make_scorer(custom_scoring_function, greater_is_better=False),
...  cv=5,
...  n_jobs=-1) 

3.4.3.3. 使用多指标评估#

Scikit-learn 还允许在 GridSearchCVRandomizedSearchCVcross_validate 中评估多个指标。

有三种方法可以为 scoring 参数指定多个评分指标

  • 作为字符串指标的迭代器

    >>> scoring = ['accuracy', 'precision']
    
  • 作为 dict,将评分器名称映射到评分函数

    >>> from sklearn.metrics import accuracy_score
    >>> from sklearn.metrics import make_scorer
    >>> scoring = {'accuracy': make_scorer(accuracy_score),
    ...            'prec': 'precision'}
    

    请注意,字典值可以是评分器函数或预定义的指标字符串之一。

  • 作为返回分数字典的可调用对象

    >>> from sklearn.model_selection import cross_validate
    >>> from sklearn.metrics import confusion_matrix
    >>> # A sample toy binary classification dataset
    >>> X, y = datasets.make_classification(n_classes=2, random_state=0)
    >>> svm = LinearSVC(random_state=0)
    >>> def confusion_matrix_scorer(clf, X, y):
    ...      y_pred = clf.predict(X)
    ...      cm = confusion_matrix(y, y_pred)
    ...      return {'tn': cm[0, 0], 'fp': cm[0, 1],
    ...              'fn': cm[1, 0], 'tp': cm[1, 1]}
    >>> cv_results = cross_validate(svm, X, y, cv=5,
    ...                             scoring=confusion_matrix_scorer)
    >>> # Getting the test set true positive scores
    >>> print(cv_results['test_tp'])
    [10  9  8  7  8]
    >>> # Getting the test set false negative scores
    >>> print(cv_results['test_fn'])
    [0 1 2 3 2]
    

3.4.4. 分类指标#

sklearn.metrics 模块实现了几种损失、得分和效用函数来衡量分类性能。某些指标可能需要正类的概率估计、置信值或二元决策值。大多数实现允许每个样本通过 sample_weight 参数对整体分数做出加权贡献。

其中一些仅限于二元分类情况。

precision_recall_curve(y_true[, y_score, ...])

计算不同概率阈值的精确率-召回率对。

roc_curve(y_true, y_score, *[, pos_label, ...])

计算接收者操作特征曲线 (ROC)。

class_likelihood_ratios(y_true, y_pred, *[, ...])

计算二元分类的正似然比和负似然比。

det_curve(y_true, y_score[, pos_label, ...])

计算不同概率阈值的错误率。

其他一些也适用于多类别情况。

balanced_accuracy_score(y_true, y_pred, *[, ...])

计算平衡精度。

cohen_kappa_score(y1, y2, *[, labels, ...])

计算 Cohen 的 kappa 系数:衡量注释者之间一致性的统计量。

confusion_matrix(y_true, y_pred, *[, ...])

计算混淆矩阵以评估分类的准确性。

hinge_loss(y_true, pred_decision, *[, ...])

平均铰链损失(非正则化)。

matthews_corrcoef(y_true, y_pred, *[, ...])

计算马修斯相关系数 (MCC)。

roc_auc_score(y_true, y_score, *[, average, ...])

根据预测分数计算接收者操作特征曲线下面积 (ROC AUC)。

top_k_accuracy_score(y_true, y_score, *[, ...])

Top-k 准确率分类分数。

一些也适用于多标签情况。

accuracy_score(y_true, y_pred, *[, ...])

准确率分类分数。

classification_report(y_true, y_pred, *[, ...])

构建显示主要分类指标的文本报告。

f1_score(y_true, y_pred, *[, labels, ...])

计算 F1 分数,也称为平衡 F 分数或 F 测度。

fbeta_score(y_true, y_pred, *, beta[, ...])

计算 F-beta 分数。

hamming_loss(y_true, y_pred, *[, sample_weight])

计算平均汉明损失。

jaccard_score(y_true, y_pred, *[, labels, ...])

Jaccard 相似系数得分。

log_loss(y_true, y_pred, *[, normalize, ...])

对数损失,也称为逻辑损失或交叉熵损失。

multilabel_confusion_matrix(y_true, y_pred, *)

为每个类别或样本计算混淆矩阵。

precision_recall_fscore_support(y_true, ...)

计算每个类别的精确率、召回率、F-测度和支持度。

precision_score(y_true, y_pred, *[, labels, ...])

计算精确率。

recall_score(y_true, y_pred, *[, labels, ...])

计算召回率。

roc_auc_score(y_true, y_score, *[, average, ...])

根据预测分数计算接收者操作特征曲线下面积 (ROC AUC)。

zero_one_loss(y_true, y_pred, *[, ...])

零一分类损失。

d2_log_loss_score(y_true, y_pred, *[, ...])

\(D^2\) 分数函数,解释的对数损失分数。

以及一些处理二元和多标签(但不是多类别)问题的函数。

average_precision_score(y_true, y_score, *)

根据预测分数计算平均精确率 (AP)。

在接下来的小节中,我们将描述每个函数,并在前面介绍一些关于常用 API 和指标定义的说明。

3.4.4.1. 从二元到多类别和多标签#

一些指标本质上是为二元分类任务定义的(例如 f1_scoreroc_auc_score)。在这些情况下,默认情况下只评估正标签,默认假设正类标记为 1(尽管这可以通过 pos_label 参数进行配置)。

将二元指标扩展到多类别或多标签问题时,数据被视为一系列二元问题的集合,每个类别一个。然后有多种方法可以对类别集上的二元指标计算进行平均,每种方法在某些情况下都可能有用。如果可用,您应该使用 average 参数在这些方法中进行选择。

  • "macro" 简单地计算二元指标的平均值,对每个类别赋予相同的权重。在不常见类别仍然重要的场合,宏平均可能是一种突出其性能的方法。另一方面,所有类别都同等重要的假设通常是不正确的,因此宏平均将过分强调在不常见类别上通常较低的性能。

  • "weighted" 通过计算二元指标的平均值来考虑类别不平衡,其中每个类别的分数按其在真实数据样本中的出现情况加权。

  • "micro" 使每个样本-类别对对整体指标的贡献相同(除非样本权重导致结果不同)。此方法不是对每个类别的指标求和,而是对构成每个类别指标的被除数和除数求和以计算整体商。在多标签设置中,可能更倾向于使用微平均,包括在需要忽略多数类别的多类别分类中。

  • "samples" 仅适用于多标签问题。它不计算每个类别的度量,而是计算评估数据中每个样本的真实类和预测类上的指标,并返回它们的(sample_weight 加权)平均值。

  • 选择 average=None 将返回一个包含每个类别分数的数组。

虽然多类别数据作为类别标签数组提供给指标,就像二元目标一样,但多标签数据则指定为指示矩阵,其中单元格 [i, j] 的值为 1 表示样本 i 具有标签 j,否则值为 0。

3.4.4.2. 准确率评分#

accuracy_score 函数计算 准确率,即正确预测的分数(默认)或计数 (normalize=False)。

在多标签分类中,该函数返回子集准确率。如果样本的整个预测标签集与真实标签集严格匹配,则子集准确率为 1.0;否则为 0.0。

如果 \(\hat{y}_i\) 是第 \(i\) 个样本的预测值,而 \(y_i\) 是相应的真实值,则 \(n_\text{samples}\) 上正确预测的分数定义为

\[\texttt{accuracy}(y, \hat{y}) = \frac{1}{n_\text{samples}} \sum_{i=0}^{n_\text{samples}-1} 1(\hat{y}_i = y_i)\]

其中 \(1(x)\)指示函数

>>> import numpy as np
>>> from sklearn.metrics import accuracy_score
>>> y_pred = [0, 2, 1, 3]
>>> y_true = [0, 1, 2, 3]
>>> accuracy_score(y_true, y_pred)
0.5
>>> accuracy_score(y_true, y_pred, normalize=False)
2.0

在具有二元标签指示符的多标签情况下

>>> accuracy_score(np.array([[0, 1], [1, 1]]), np.ones((2, 2)))
0.5

示例

3.4.4.3. Top-k 准确率评分#

函数 top_k_accuracy_scoreaccuracy_score 的推广。区别在于,只要真实标签与预测得分最高的 k 个预测结果之一关联,则预测就被认为是正确的。accuracy_scorek = 1 的特例。

该函数涵盖二元和多类分类情况,但不包括多标签情况。

如果 \(\hat{f}_{i,j}\) 是第 \(i\) 个样本对应的第 \(j\) 个最大预测分数的预测类别,而 \(y_i\) 是对应的真实值,则 \(n_\text{samples}\) 上正确预测的比例定义为

\[\texttt{top-k accuracy}(y, \hat{f}) = \frac{1}{n_\text{samples}} \sum_{i=0}^{n_\text{samples}-1} \sum_{j=1}^{k} 1(\hat{f}_{i,j} = y_i)\]

其中 \(k\) 是允许的猜测次数,\(1(x)\)指示函数

>>> import numpy as np
>>> from sklearn.metrics import top_k_accuracy_score
>>> y_true = np.array([0, 1, 2, 2])
>>> y_score = np.array([[0.5, 0.2, 0.2],
...                     [0.3, 0.4, 0.2],
...                     [0.2, 0.4, 0.3],
...                     [0.7, 0.2, 0.1]])
>>> top_k_accuracy_score(y_true, y_score, k=2)
0.75
>>> # Not normalizing gives the number of "correctly" classified samples
>>> top_k_accuracy_score(y_true, y_score, k=2, normalize=False)
3

3.4.4.4. 平衡准确率#

函数 balanced_accuracy_score 计算 平衡准确率,避免在不平衡数据集上夸大性能估计。它是每个类别的召回率的宏平均值,或者等效地,每个样本根据其真实类别的逆流行度加权的原始准确率。因此,对于平衡数据集,该分数等于准确率。

在二元情况下,平衡准确率等于 灵敏度(真阳性率)和 特异性(真阴性率)的算术平均值,或者使用二元预测而不是分数的ROC曲线下的面积。

\[\texttt{balanced-accuracy} = \frac{1}{2}\left( \frac{TP}{TP + FN} + \frac{TN}{TN + FP}\right )\]

如果分类器在任一类上的性能都一样好,则此项将简化为常规准确率(即,正确预测的数量除以预测的总数)。

相反,如果常规准确率高于偶然性仅仅是因为分类器利用了不平衡的测试集,则平衡准确率将适当下降到 \(\frac{1}{n\_classes}\)

分数范围从0到1,或者当使用 adjusted=True 时,它重新缩放到范围 \(\frac{1}{1 - n\_classes}\) 到1(包含),随机预测的性能得分为0。

如果 \(y_i\) 是第 \(i\) 个样本的真实值,而 \(w_i\) 是对应的样本权重,则我们将样本权重调整为

\[\hat{w}_i = \frac{w_i}{\sum_j{1(y_j = y_i) w_j}}\]

其中 \(1(x)\)指示函数。给定样本 \(i\) 的预测 \(\hat{y}_i\),平衡准确率定义为

\[\texttt{balanced-accuracy}(y, \hat{y}, w) = \frac{1}{\sum{\hat{w}_i}} \sum_i 1(\hat{y}_i = y_i) \hat{w}_i\]

使用 adjusted=True,平衡准确率报告了相对于 \(\texttt{balanced-accuracy}(y, \mathbf{0}, w) = \frac{1}{n\_classes}\) 的相对增加。在二元情况下,这也称为 *Youden's J统计量* 或 *知情度*。

注意

此处多类定义似乎是二元分类中使用的度量的最合理的扩展,尽管文献中没有明确的共识。

  • 我们的定义:[Mosley2013][Kelleher2015][Guyon2015],其中 [Guyon2015] 采用调整后的版本以确保随机预测的分数为 \(0\),完美预测的分数为 \(1\)

  • [Mosley2013] 中描述的类别平衡准确率:计算每个类别的精确率和召回率中的最小值。然后将这些值平均到总类别数以获得平衡准确率。

  • [Urbanowicz2015] 中描述的平衡准确率:计算每个类的灵敏度和特异性的平均值,然后平均到总类别数。

参考文献

[Guyon2015] (1,2)

I. Guyon, K. Bennett, G. Cawley, H.J. Escalante, S. Escalera, T.K. Ho, N. Macià, B. Ray, M. Saeed, A.R. Statnikov, E. Viegas, 2015 ChaLearn AutoML 挑战赛的设计,IJCNN 2015。

[Mosley2013] (1,2)

L. Mosley, 一种解决多类不平衡问题的平衡方法,IJCV 2010。

[Kelleher2015]

John. D. Kelleher, Brian Mac Namee, Aoife D’Arcy, 预测数据分析的机器学习基础:算法、实例和案例研究,2015。

[Urbanowicz2015]

Urbanowicz R.J.,Moore, J.H. ExSTraCS 2.0:可扩展学习分类系统的描述和评估,Evol. Intel. (2015) 8: 89。

3.4.4.5. Cohen Kappa 系数#

函数 cohen_kappa_score 计算Cohen 的 kappa 系数。此度量旨在比较不同人类标注者的标注结果,而不是分类器与真实值之间的比较。

kappa 系数是一个介于 -1 和 1 之间的数字。高于 0.8 的分数通常被认为是一致性良好;零或更低表示没有一致性(实际上是随机标签)。

kappa 系数可以用于二元或多类问题,但不能用于多标签问题(除非手动计算每个标签的分数),也不能用于两个以上标注者。

>>> from sklearn.metrics import cohen_kappa_score
>>> labeling1 = [2, 0, 2, 2, 0, 1]
>>> labeling2 = [0, 0, 2, 2, 0, 2]
>>> cohen_kappa_score(labeling1, labeling2)
0.4285714285714286

3.4.4.6. 混淆矩阵#

confusion_matrix 函数通过计算混淆矩阵来评估分类精度,其中每一行对应于真实类别(维基百科和其他参考资料可能对轴使用不同的约定)。

根据定义,混淆矩阵中 \(i, j\) 项是实际属于组 \(i\) 但被预测为属于组 \(j\) 的观测数。这是一个例子

>>> from sklearn.metrics import confusion_matrix
>>> y_true = [2, 0, 2, 2, 0, 1]
>>> y_pred = [0, 0, 2, 2, 0, 2]
>>> confusion_matrix(y_true, y_pred)
array([[2, 0, 0],
       [0, 0, 1],
       [1, 0, 2]])

ConfusionMatrixDisplay 可用于直观地表示混淆矩阵,如混淆矩阵示例所示,该示例创建了以下图形

../_images/sphx_glr_plot_confusion_matrix_001.png

参数 normalize 允许报告比率而不是计数。混淆矩阵可以通过三种不同的方式进行归一化:'pred''true''all',它们将分别按各列、各行或整个矩阵的总和除以计数。

>>> y_true = [0, 0, 0, 1, 1, 1, 1, 1]
>>> y_pred = [0, 1, 0, 1, 0, 1, 0, 1]
>>> confusion_matrix(y_true, y_pred, normalize='all')
array([[0.25 , 0.125],
       [0.25 , 0.375]])

对于二元问题,我们可以得到真阴性、假阳性、假阴性和真阳性的计数,如下所示

>>> y_true = [0, 0, 0, 1, 1, 1, 1, 1]
>>> y_pred = [0, 1, 0, 1, 0, 1, 0, 1]
>>> tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
>>> tn, fp, fn, tp
(2, 1, 2, 3)

示例

3.4.4.7. 分类报告#

classification_report 函数构建一个文本报告,显示主要的分类指标。这是一个使用自定义 target_names 和推断标签的小示例

>>> from sklearn.metrics import classification_report
>>> y_true = [0, 1, 2, 2, 0]
>>> y_pred = [0, 0, 2, 1, 0]
>>> target_names = ['class 0', 'class 1', 'class 2']
>>> print(classification_report(y_true, y_pred, target_names=target_names))
              precision    recall  f1-score   support

     class 0       0.67      1.00      0.80         2
     class 1       0.00      0.00      0.00         1
     class 2       1.00      0.50      0.67         2

    accuracy                           0.60         5
   macro avg       0.56      0.50      0.49         5
weighted avg       0.67      0.60      0.59         5

示例

3.4.4.8. 汉明损失#

hamming_loss 计算两组样本之间的平均汉明损失或汉明距离

如果 \(\hat{y}_{i,j}\) 是给定样本 \(i\) 的第 \(j\) 个标签的预测值,\(y_{i,j}\) 是对应的真实值,\(n_\text{samples}\) 是样本数,\(n_\text{labels}\) 是标签数,则汉明损失 \(L_{Hamming}\) 定义为

\[L_{Hamming}(y, \hat{y}) = \frac{1}{n_\text{samples} * n_\text{labels}} \sum_{i=0}^{n_\text{samples}-1} \sum_{j=0}^{n_\text{labels} - 1} 1(\hat{y}_{i,j} \not= y_{i,j})\]

其中 \(1(x)\)指示函数

上述等式在多类分类的情况下不成立。有关更多信息,请参阅下面的说明。

>>> from sklearn.metrics import hamming_loss
>>> y_pred = [1, 2, 3, 4]
>>> y_true = [2, 2, 3, 4]
>>> hamming_loss(y_true, y_pred)
0.25

在具有二元标签指示符的多标签情况下

>>> hamming_loss(np.array([[0, 1], [1, 1]]), np.zeros((2, 2)))
0.75

注意

在多类分类中,汉明损失对应于 y_truey_pred 之间的汉明距离,这类似于零一损失函数。但是,虽然零一损失会惩罚与真实集合不完全匹配的预测集合,但汉明损失会惩罚单个标签。因此,汉明损失的上限为零一损失,始终介于零和一之间(包含零和一);预测真实标签的真子集或真超集将得到一个介于零和一之间的汉明损失(不包含零和一)。

3.4.4.9. 精确率、召回率和 F 值#

直观地说,精确率 是分类器不将负样本标记为正样本的能力,而召回率 是分类器找到所有正样本的能力。

F 值\(F_\beta\)\(F_1\) 值)可以解释为精确率和召回率的加权调和平均值。\(F_\beta\) 值的最佳值为 1,最差值为 0。当 \(\beta = 1\) 时,\(F_\beta\)\(F_1\) 等效,召回率和精确率同等重要。

precision_recall_curve 通过改变决策阈值,根据真实标签和分类器给出的分数计算精确率-召回率曲线。

average_precision_score 函数根据预测分数计算平均精确率 (AP)。该值介于 0 和 1 之间,越高越好。AP 定义为

\[\text{AP} = \sum_n (R_n - R_{n-1}) P_n\]

其中\(P_n\)\(R_n\)是第n个阈值的精确率和召回率。在随机预测中,平均精确率 (AP) 是正样本的比例。

参考文献[Manning2008][Everingham2010]提出了AP的替代变体,这些变体对精确率-召回率曲线进行插值。目前,average_precision_score没有实现任何插值变体。参考文献[Davis2006][Flach2015]描述了为什么对精确率-召回率曲线上的点进行线性插值会提供一个过于乐观的分类器性能度量。在使用梯形法则计算曲线下面积时,auc使用了这种线性插值。

几个函数允许你分析精确率、召回率和F值。

average_precision_score(y_true, y_score, *)

根据预测分数计算平均精确率 (AP)。

f1_score(y_true, y_pred, *[, labels, ...])

计算 F1 分数,也称为平衡 F 分数或 F 测度。

fbeta_score(y_true, y_pred, *, beta[, ...])

计算 F-beta 分数。

precision_recall_curve(y_true[, y_score, ...])

计算不同概率阈值的精确率-召回率对。

precision_recall_fscore_support(y_true, ...)

计算每个类别的精确率、召回率、F-测度和支持度。

precision_score(y_true, y_pred, *[, labels, ...])

计算精确率。

recall_score(y_true, y_pred, *[, labels, ...])

计算召回率。

请注意,precision_recall_curve函数仅限于二元分类。 average_precision_score函数通过以一对多 (OvR) 的方式计算每个类的分数并根据其average参数值进行平均或不平均来支持多类别和多标签格式。

PrecisionRecallDisplay.from_estimatorPrecisionRecallDisplay.from_predictions函数将绘制精确率-召回率曲线,如下所示。

../_images/sphx_glr_plot_precision_recall_001.png

示例

参考文献

[Manning2008]

C.D. Manning, P. Raghavan, H. Schütze, 信息检索导论, 2008.

[Everingham2010]

M. Everingham, L. Van Gool, C.K.I. Williams, J. Winn, A. Zisserman, Pascal视觉对象类别(VOC)挑战赛, IJCV 2010.

3.4.4.9.1. 二元分类#

在二元分类任务中,“正”和“负”指的是分类器的预测,“真”和“假”指的是该预测是否与外部判断(有时称为“观察”)相符。根据这些定义,我们可以制定下表

实际类别(观察值)

预测类别(预期值)

tp(真阳性) 正确结果

fp(假阳性) 意外结果

fn(假阴性) 缺失结果

tn(真阴性) 正确的无结果

在此上下文中,我们可以定义精确率和召回率的概念

\[\text{精确率} = \frac{\text{tp}}{\text{tp} + \text{fp}},\]
\[\text{召回率} = \frac{\text{tp}}{\text{tp} + \text{fn}},\]

(有时召回率也称为“灵敏度”)

F值是精确率和召回率的加权调和平均数,其中精确率对平均值的贡献由某个参数\(\beta\)加权。

\[F_\beta = (1 + \beta^2) \frac{\text{精确率} \times \text{召回率}}{\beta^2 \text{精确率} + \text{召回率}}\]

为了避免在精确率和召回率为零时出现除以零的情况,Scikit-Learn 使用以下等效公式计算 F 值:

\[F_\beta = \frac{(1 + \beta^2) \text{tp}}{(1 + \beta^2) \text{tp} + \text{fp} + \beta^2 \text{fn}}\]

请注意,当没有真阳性、假阳性或假阴性时,此公式仍然未定义。默认情况下,对于一组完全为真阴性的样本,F-1 计算结果为 0,但是可以使用zero_division参数更改此行为。以下是一些二元分类中的小例子

>>> from sklearn import metrics
>>> y_pred = [0, 1, 0, 0]
>>> y_true = [0, 1, 0, 1]
>>> metrics.precision_score(y_true, y_pred)
1.0
>>> metrics.recall_score(y_true, y_pred)
0.5
>>> metrics.f1_score(y_true, y_pred)
0.66...
>>> metrics.fbeta_score(y_true, y_pred, beta=0.5)
0.83...
>>> metrics.fbeta_score(y_true, y_pred, beta=1)
0.66...
>>> metrics.fbeta_score(y_true, y_pred, beta=2)
0.55...
>>> metrics.precision_recall_fscore_support(y_true, y_pred, beta=0.5)
(array([0.66..., 1.        ]), array([1. , 0.5]), array([0.71..., 0.83...]), array([2, 2]))


>>> import numpy as np
>>> from sklearn.metrics import precision_recall_curve
>>> from sklearn.metrics import average_precision_score
>>> y_true = np.array([0, 0, 1, 1])
>>> y_scores = np.array([0.1, 0.4, 0.35, 0.8])
>>> precision, recall, threshold = precision_recall_curve(y_true, y_scores)
>>> precision
array([0.5       , 0.66..., 0.5       , 1.        , 1.        ])
>>> recall
array([1. , 1. , 0.5, 0.5, 0. ])
>>> threshold
array([0.1 , 0.35, 0.4 , 0.8 ])
>>> average_precision_score(y_true, y_scores)
0.83...

3.4.4.9.2. 多类别和多标签分类#

在多类别和多标签分类任务中,精确率、召回率和F值的概念可以独立应用于每个标签。有几种方法可以组合跨标签的结果,由average_precision_scoref1_scorefbeta_scoreprecision_recall_fscore_supportprecision_scorerecall_score函数的average参数指定,如上文所述。

请注意平均时的以下行为:

  • 如果包含所有标签,则在多类别设置中,“微”平均将产生精确率、召回率和\(F\)值,它们都与准确率相同。

  • “加权”平均可能会产生一个不在精确率和召回率之间的F值。

  • F 值的“宏”(macro)平均计算为每个标签/类的 F 值的算术平均值,而不是算术平均精度和召回率的调和平均值。这两种计算方法在文献中都有出现,但并不等价,详情请参见[OB2019]

为了更明确地说明这一点,请考虑以下符号

  • \(y\) 表示真实\((样本, 标签)\) 对的集合

  • \(\hat{y}\) 表示预测\((样本, 标签)\) 对的集合

  • \(L\) 表示标签的集合

  • \(S\) 表示样本的集合

  • \(y_s\) 表示样本 \(s\)\(y\) 子集,即 \(y_s := \left\{(s', l) \in y | s' = s\right\}\)

  • \(y_l\) 表示标签 \(l\)\(y\) 子集

  • 类似地,\(\hat{y}_s\)\(\hat{y}_l\)\(\hat{y}\) 的子集

  • \(P(A, B) := \frac{\left| A \cap B \right|}{\left|B\right|}\) 对于某些集合 \(A\)\(B\)

  • \(R(A, B) := \frac{\left| A \cap B \right|}{\left|A\right|}\) (关于处理 \(A = \emptyset\) 的约定有所不同;此实现使用 \(R(A, B):=0\)\(P\) 类似。)

  • \(F_\beta(A, B) := \left(1 + \beta^2\right) \frac{P(A, B) \times R(A, B)}{\beta^2 P(A, B) + R(A, B)}\)

然后指标定义为:

平均值

精确率

召回率

F_β

“微”(micro)

\(P(y, \hat{y})\)

\(R(y, \hat{y})\)

\(F_\beta(y, \hat{y})\)

“样本”(samples)

\(\frac{1}{\left|S\right|} \sum_{s \in S} P(y_s, \hat{y}_s)\)

\(\frac{1}{\left|S\right|} \sum_{s \in S} R(y_s, \hat{y}_s)\)

\(\frac{1}{\left|S\right|} \sum_{s \in S} F_\beta(y_s, \hat{y}_s)\)

“宏”(macro)

\(\frac{1}{\left|L\right|} \sum_{l \in L} P(y_l, \hat{y}_l)\)

\(\frac{1}{\left|L\right|} \sum_{l \in L} R(y_l, \hat{y}_l)\)

\(\frac{1}{\left|L\right|} \sum_{l \in L} F_\beta(y_l, \hat{y}_l)\)

“加权”(weighted)

\(\frac{1}{\sum_{l \in L} \left|y_l\right|} \sum_{l \in L} \left|y_l\right| P(y_l, \hat{y}_l)\)

\(\frac{1}{\sum_{l \in L} \left|y_l\right|} \sum_{l \in L} \left|y_l\right| R(y_l, \hat{y}_l)\)

\(\frac{1}{\sum_{l \in L} \left|y_l\right|} \sum_{l \in L} \left|y_l\right| F_\beta(y_l, \hat{y}_l)\)

\(\langle P(y_l, \hat{y}_l) | l \in L \rangle\)

\(\langle R(y_l, \hat{y}_l) | l \in L \rangle\)

\(\langle F_\beta(y_l, \hat{y}_l) | l \in L \rangle\)

>>> from sklearn import metrics
>>> y_true = [0, 1, 2, 0, 1, 2]
>>> y_pred = [0, 2, 1, 0, 0, 1]
>>> metrics.precision_score(y_true, y_pred, average='macro')
0.22...
>>> metrics.recall_score(y_true, y_pred, average='micro')
0.33...
>>> metrics.f1_score(y_true, y_pred, average='weighted')
0.26...
>>> metrics.fbeta_score(y_true, y_pred, average='macro', beta=0.5)
0.23...
>>> metrics.precision_recall_fscore_support(y_true, y_pred, beta=0.5, average=None)
(array([0.66..., 0.        , 0.        ]), array([1., 0., 0.]), array([0.71..., 0.        , 0.        ]), array([2, 2, 2]...))

对于具有“负类”的多分类问题,可以排除某些标签。

>>> metrics.recall_score(y_true, y_pred, labels=[1, 2], average='micro')
... # excluding 0, no labels were correctly recalled
0.0

类似地,宏平均可以考虑数据样本中不存在的标签。

>>> metrics.precision_score(y_true, y_pred, labels=[0, 1, 2, 3], average='macro')
0.166...

参考文献

3.4.4.10. Jaccard 相似系数得分#

jaccard_score 函数计算标签集对之间的 Jaccard 相似系数(也称为 Jaccard 指数)的平均值。

给定真实标签集 \(y\) 和预测标签集 \(\hat{y}\),Jaccard 相似系数定义为:

\[J(y, \hat{y}) = \frac{|y \cap \hat{y}|}{|y \cup \hat{y}|}.\]

jaccard_score(与 precision_recall_fscore_support 一样)原生应用于二元目标。通过集合方式计算,它可以通过使用 average 扩展到多标签和多类别问题(见上文)。

在二元情况下

>>> import numpy as np
>>> from sklearn.metrics import jaccard_score
>>> y_true = np.array([[0, 1, 1],
...                    [1, 1, 0]])
>>> y_pred = np.array([[1, 1, 1],
...                    [1, 0, 0]])
>>> jaccard_score(y_true[0], y_pred[0])
0.6666...

在二维比较情况下(例如图像相似性)

>>> jaccard_score(y_true, y_pred, average="micro")
0.6

在具有二元标签指示符的多标签情况下

>>> jaccard_score(y_true, y_pred, average='samples')
0.5833...
>>> jaccard_score(y_true, y_pred, average='macro')
0.6666...
>>> jaccard_score(y_true, y_pred, average=None)
array([0.5, 0.5, 1. ])

多类别问题被二值化,并像相应的多标签问题一样处理。

>>> y_pred = [0, 2, 1, 2]
>>> y_true = [0, 1, 2, 2]
>>> jaccard_score(y_true, y_pred, average=None)
array([1. , 0. , 0.33...])
>>> jaccard_score(y_true, y_pred, average='macro')
0.44...
>>> jaccard_score(y_true, y_pred, average='micro')
0.33...

3.4.4.11. 铰链损失#

hinge_loss 函数使用 铰链损失 计算模型与数据之间的平均距离,这是一种单侧度量,仅考虑预测误差。(铰链损失用于支持向量机等最大间隔分类器。)

如果二元分类任务的真实标签 \(y_i\) 对于每个样本 \(i\) 都编码为 \(y_i=\left\{-1, +1\right\}\);并且 \(w_i\) 是相应的预测决策(由 decision_function 方法输出的形状为 (n_samples,) 的数组),则铰链损失定义为:

\[L_\text{Hinge}(y, w) = \frac{1}{n_\text{samples}} \sum_{i=0}^{n_\text{samples}-1} \max\left\{1 - w_i y_i, 0\right\}\]

如果有多于两个标签,hinge_loss 使用 Crammer & Singer 提出的多类别变体。此处 是描述它的论文。

在这种情况下,预测决策是一个形状为 (n_samples, n_labels) 的数组。如果 \(w_{i, y_i}\) 是第 \(i\) 个样本的真实标签 \(y_i\) 的预测决策;并且 \(\hat{w}_{i, y_i} = \max\left\{w_{i, y_j}~|~y_j \ne y_i \right\}\) 是所有其他标签的预测决策的最大值,则多类别铰链损失定义为:

\[L_\text{Hinge}(y, w) = \frac{1}{n_\text{samples}} \sum_{i=0}^{n_\text{samples}-1} \max\left\{1 + \hat{w}_{i, y_i} - w_{i, y_i}, 0\right\}\]

这是一个小型示例,演示了在二元类问题中使用 hinge_loss 函数与 svm 分类器。

>>> from sklearn import svm
>>> from sklearn.metrics import hinge_loss
>>> X = [[0], [1]]
>>> y = [-1, 1]
>>> est = svm.LinearSVC(random_state=0)
>>> est.fit(X, y)
LinearSVC(random_state=0)
>>> pred_decision = est.decision_function([[-2], [3], [0.5]])
>>> pred_decision
array([-2.18...,  2.36...,  0.09...])
>>> hinge_loss([-1, 1, 1], pred_decision)
0.3...

这是一个示例,演示了在多类别问题中使用 hinge_loss 函数与 svm 分类器。

>>> X = np.array([[0], [1], [2], [3]])
>>> Y = np.array([0, 1, 2, 3])
>>> labels = np.array([0, 1, 2, 3])
>>> est = svm.LinearSVC()
>>> est.fit(X, Y)
LinearSVC()
>>> pred_decision = est.decision_function([[-1], [2], [3]])
>>> y_true = [0, 2, 3]
>>> hinge_loss(y_true, pred_decision, labels=labels)
0.56...

3.4.4.12. 对数损失#

对数损失,也称为逻辑回归损失或交叉熵损失,是在概率估计上定义的。它通常用于(多项式)逻辑回归和神经网络,以及期望最大化的一些变体,并且可以用来评估分类器的概率输出(predict_proba),而不是它的离散预测。

对于二元分类,真标签为\(y \in \{0,1\}\),概率估计为\(p = \operatorname{Pr}(y = 1)\),则每个样本的对数损失是给定真标签下分类器的负对数似然。

\[L_{\log}(y, p) = -\log \operatorname{Pr}(y|p) = -(y \log (p) + (1 - y) \log (1 - p))\]

这可以扩展到多类别情况。设一组样本的真标签编码为一个K维的独热编码矩阵\(Y\),即如果样本\(i\)的标签为来自\(K\)个标签集合中的\(k\),则\(y_{i,k} = 1\)。设\(P\)为概率估计矩阵,其中\(p_{i,k} = \operatorname{Pr}(y_{i,k} = 1)\)。则整个集合的对数损失为

\[L_{\log}(Y, P) = -\log \operatorname{Pr}(Y|P) = - \frac{1}{N} \sum_{i=0}^{N-1} \sum_{k=0}^{K-1} y_{i,k} \log p_{i,k}\]

为了了解这如何推广上述二元对数损失,请注意,在二元情况下,\(p_{i,0} = 1 - p_{i,1}\)\(y_{i,0} = 1 - y_{i,1}\),因此对\(y_{i,k} \in \{0,1\}\)的内和进行展开会得到二元对数损失。

log_loss 函数根据真标签列表和概率矩阵计算对数损失,概率矩阵由估计器的 predict_proba 方法返回。

>>> from sklearn.metrics import log_loss
>>> y_true = [0, 0, 1, 1]
>>> y_pred = [[.9, .1], [.8, .2], [.3, .7], [.01, .99]]
>>> log_loss(y_true, y_pred)
0.1738...

y_pred 中的第一个 [.9, .1] 表示第一个样本的标签为 0 的概率为 90%。对数损失是非负的。

3.4.4.13. 马修斯相关系数#

matthews_corrcoef 函数计算二元类别的马修斯相关系数 (MCC)。引用维基百科:

“马修斯相关系数在机器学习中用作衡量二元(两类)分类质量的指标。它考虑了真阳性、真阴性、假阳性和假阴性,并且通常被认为是一个平衡的度量,即使类别大小差异很大也可以使用。MCC 本质上是一个介于 -1 和 +1 之间的相关系数值。+1 系数表示完美的预测,0 表示平均随机预测,-1 表示反向预测。该统计量也称为 phi 系数。”

在二元(两类)情况下,\(tp\)\(tn\)\(fp\)\(fn\) 分别是真阳性、真阴性、假阳性和假阴性的数量,MCC 定义为

\[MCC = \frac{tp \times tn - fp \times fn}{\sqrt{(tp + fp)(tp + fn)(tn + fp)(tn + fn)}}.\]

在多类别情况下,马修斯相关系数可以定义\(K\)个类别的confusion_matrix \(C\)。为了简化定义,考虑以下中间变量:

  • \(t_k=\sum_{i}^{K} C_{ik}\) 类别 \(k\) 真实出现的次数,

  • \(p_k=\sum_{i}^{K} C_{ki}\) 预测类别 \(k\) 的次数,

  • \(c=\sum_{k}^{K} C_{kk}\) 正确预测的样本总数,

  • \(s=\sum_{i}^{K} \sum_{j}^{K} C_{ij}\) 样本总数。

则多类别 MCC 定义为

\[MCC = \frac{ c \times s - \sum_{k}^{K} p_k \times t_k }{\sqrt{ (s^2 - \sum_{k}^{K} p_k^2) \times (s^2 - \sum_{k}^{K} t_k^2) }}\]

当标签超过两个时,MCC 的值将不再介于 -1 和 +1 之间。相反,最小值将介于 -1 和 0 之间,具体取决于真实标签的数量和分布。最大值始终为 +1。更多信息,请参见 [WikipediaMCC2021]

这是一个小的例子,说明了 matthews_corrcoef 函数的用法。

>>> from sklearn.metrics import matthews_corrcoef
>>> y_true = [+1, +1, +1, -1]
>>> y_pred = [+1, -1, +1, +1]
>>> matthews_corrcoef(y_true, y_pred)
-0.33...

参考文献

[WikipediaMCC2021]

维基百科贡献者。Phi 系数。维基百科,自由的百科全书。2021 年 4 月 21 日,12:21 中欧夏令时。网址:https://en.wikipedia.org/wiki/Phi_coefficient 2021 年 4 月 21 日访问。

3.4.4.14. 多标签混淆矩阵#

multilabel_confusion_matrix 函数计算逐类(默认)或逐样本(samplewise=True)多标签混淆矩阵,以评估分类的准确性。multilabel_confusion_matrix 还将多类别数据视为多标签数据,因为这是一种常用转换,用于使用二元分类指标(如精确度、召回率等)评估多类别问题。

计算逐类多标签混淆矩阵 \(C\) 时,类别 \(i\) 的真阴性计数为 \(C_{i,0,0}\),假阴性为 \(C_{i,1,0}\),真阳性为 \(C_{i,1,1}\),假阳性为 \(C_{i,0,1}\)

这是一个演示如何使用 multilabel_confusion_matrix 函数以及 多标签指示矩阵 输入的示例。

>>> import numpy as np
>>> from sklearn.metrics import multilabel_confusion_matrix
>>> y_true = np.array([[1, 0, 1],
...                    [0, 1, 0]])
>>> y_pred = np.array([[1, 0, 0],
...                    [0, 1, 1]])
>>> multilabel_confusion_matrix(y_true, y_pred)
array([[[1, 0],
        [0, 1]],

       [[1, 0],
        [0, 1]],

       [[0, 1],
        [1, 0]]])

或者,可以为每个样本的标签构建混淆矩阵。

>>> multilabel_confusion_matrix(y_true, y_pred, samplewise=True)
array([[[1, 0],
        [1, 1]],

       [[1, 1],
        [0, 1]]])

这是一个演示如何使用 multilabel_confusion_matrix 函数以及 多类别 输入的示例。

>>> y_true = ["cat", "ant", "cat", "cat", "ant", "bird"]
>>> y_pred = ["ant", "ant", "cat", "cat", "ant", "cat"]
>>> multilabel_confusion_matrix(y_true, y_pred,
...                             labels=["ant", "bird", "cat"])
array([[[3, 1],
        [0, 2]],

       [[5, 0],
        [1, 0]],

       [[2, 1],
        [1, 2]]])

以下是一些演示如何使用 multilabel_confusion_matrix 函数来计算多标签指示矩阵输入问题中每个类别的召回率(或灵敏度)、特异性、虚报率和漏报率的示例。

计算每个类别的召回率(也称为真阳性率或灵敏度)。

>>> y_true = np.array([[0, 0, 1],
...                    [0, 1, 0],
...                    [1, 1, 0]])
>>> y_pred = np.array([[0, 1, 0],
...                    [0, 0, 1],
...                    [1, 1, 0]])
>>> mcm = multilabel_confusion_matrix(y_true, y_pred)
>>> tn = mcm[:, 0, 0]
>>> tp = mcm[:, 1, 1]
>>> fn = mcm[:, 1, 0]
>>> fp = mcm[:, 0, 1]
>>> tp / (tp + fn)
array([1. , 0.5, 0. ])

计算每个类别的特异性(也称为真阴性率)。

>>> tn / (tn + fp)
array([1. , 0. , 0.5])

计算每个类别的虚报率(也称为假阳性率)。

>>> fp / (fp + tn)
array([0. , 1. , 0.5])

计算每个类别的漏报率(也称为假阴性率)。

>>> fn / (fn + tp)
array([0. , 0.5, 1. ])

3.4.4.15. 受试者工作特征曲线 (ROC)#

函数 roc_curve 计算受试者工作特征曲线,或 ROC 曲线。引用维基百科:

“受试者工作特征 (ROC) 曲线,或简称 ROC 曲线,是一个图形图,它在改变判别阈值时说明二元分类器系统的性能。它是通过绘制在各种阈值设置下,真阳性占阳性的比例 (TPR = 真阳性率) 与假阳性占阴性的比例 (FPR = 假阳性率) 来创建的。TPR 也称为灵敏度,而 FPR 则是一减去特异性或真阴性率。”

此函数需要真实的二元值和目标分数,目标分数可以是阳性类的概率估计、置信值或二元决策。这是一个关于如何使用 roc_curve 函数的小示例。

>>> import numpy as np
>>> from sklearn.metrics import roc_curve
>>> y = np.array([1, 1, 2, 2])
>>> scores = np.array([0.1, 0.4, 0.35, 0.8])
>>> fpr, tpr, thresholds = roc_curve(y, scores, pos_label=2)
>>> fpr
array([0. , 0. , 0.5, 0.5, 1. ])
>>> tpr
array([0. , 0.5, 0.5, 1. , 1. ])
>>> thresholds
array([ inf, 0.8 , 0.4 , 0.35, 0.1 ])

与子集精度、汉明损失或 F1 分数等指标相比,ROC 不需要为每个标签优化阈值。

roc_auc_score 函数(用 ROC-AUC 或 AUROC 表示)计算 ROC 曲线下的面积。通过这样做,曲线信息将总结在一个数字中。

下图显示了旨在区分维吉尼亚鸢尾花与鸢尾植物数据集中其余物种的分类器的 ROC 曲线和 ROC-AUC 分数。

../_images/sphx_glr_plot_roc_001.png

有关更多信息,请参见关于 AUC 的维基百科文章

3.4.4.15.1. 二元情况#

在**二元情况下**,您可以使用 classifier.predict_proba() 方法提供的概率估计,或使用 classifier.decision_function() 方法给出的非阈值决策值。在提供概率估计的情况下,应提供具有“较大标签”的类的概率。“较大标签”对应于 classifier.classes_[1],因此为 classifier.predict_proba(X)[:, 1]。因此,y_score 参数的大小为 (n_samples,)。

>>> from sklearn.datasets import load_breast_cancer
>>> from sklearn.linear_model import LogisticRegression
>>> from sklearn.metrics import roc_auc_score
>>> X, y = load_breast_cancer(return_X_y=True)
>>> clf = LogisticRegression(solver="liblinear").fit(X, y)
>>> clf.classes_
array([0, 1])

我们可以使用对应于 clf.classes_[1] 的概率估计。

>>> y_score = clf.predict_proba(X)[:, 1]
>>> roc_auc_score(y, y_score)
0.99...

否则,我们可以使用非阈值决策值。

>>> roc_auc_score(y, clf.decision_function(X))
0.99...

3.4.4.15.2. 多类别情况#

roc_auc_score 函数也可用于**多类别分类**。目前支持两种平均策略:一对一算法计算成对 ROC AUC 分数的平均值,而一对其余算法计算针对所有其他类的每个类的 ROC AUC 分数的平均值。在这两种情况下,预测的标签都以一个值为 0 到 n_classes 的数组提供,并且分数对应于样本属于特定类的概率估计。OvO 和 OvR 算法支持统一加权(average='macro')和按流行度加权(average='weighted')。

一对一算法#

计算所有可能的类别成对组合的平均 AUC。[HT2001] 定义了一个统一加权的多类别 AUC 度量。

\[\frac{1}{c(c-1)}\sum_{j=1}^{c}\sum_{k > j}^c (\text{AUC}(j | k) + \text{AUC}(k | j))\]

其中\(c\)是类别数,\(\text{AUC}(j | k)\)是将类别\(j\)作为正类,类别\(k\)作为负类的AUC值。一般情况下,在多类别情况下,\(\text{AUC}(j | k) \neq \text{AUC}(k | j))\)。该算法通过将关键字参数multiclass设置为'ovo',并将average设置为'macro'来实现。

[HT2001]提出的多类别AUC度量可以扩展为按流行度加权

\[\frac{1}{c(c-1)}\sum_{j=1}^{c}\sum_{k > j}^c p(j \cup k)( \text{AUC}(j | k) + \text{AUC}(k | j))\]

其中\(c\)是类别数。该算法通过将关键字参数multiclass设置为'ovo',并将average设置为'weighted'来实现。'weighted'选项返回如[FC2009]中所述的流行度加权平均值。

一对多算法#

计算每个类别相对于其余类别的AUC值 [PD2000]。该算法的功能与多标签情况相同。要启用此算法,请将关键字参数multiclass设置为'ovr'。除了[F2006]中的'macro'[F2001]中的'weighted'平均之外,OvR还支持'micro'平均。

在不能容忍高误报率的应用中,可以使用roc_auc_scoremax_fpr参数将ROC曲线总结到给定的限制。

下图显示了用于区分鸢尾花数据集中不同物种的分类器的微平均ROC曲线及其相应的ROC-AUC得分。

../_images/sphx_glr_plot_roc_002.png

3.4.4.15.3. 多标签情况#

在**多标签分类**中,roc_auc_score函数通过对标签进行平均来扩展,如上文所述。在这种情况下,应提供形状为(n_samples, n_classes)y_score。因此,当使用概率估计时,需要为每个输出选择具有较大标签的类别的概率。

>>> from sklearn.datasets import make_multilabel_classification
>>> from sklearn.multioutput import MultiOutputClassifier
>>> X, y = make_multilabel_classification(random_state=0)
>>> inner_clf = LogisticRegression(solver="liblinear", random_state=0)
>>> clf = MultiOutputClassifier(inner_clf).fit(X, y)
>>> y_score = np.transpose([y_pred[:, 1] for y_pred in clf.predict_proba(X)])
>>> roc_auc_score(y, y_score, average=None)
array([0.82..., 0.86..., 0.94..., 0.85... , 0.94...])

而决策值不需要这种处理。

>>> from sklearn.linear_model import RidgeClassifierCV
>>> clf = RidgeClassifierCV().fit(X, y)
>>> y_score = clf.decision_function(X)
>>> roc_auc_score(y, y_score, average=None)
array([0.81..., 0.84... , 0.93..., 0.87..., 0.94...])

示例

参考文献

[HT2001] (1,2)

Hand, D.J. and Till, R.J., (2001). A simple generalisation of the area under the ROC curve for multiple class classification problems. Machine learning, 45(2), pp. 171-186.

[FC2009]

Ferri, Cèsar & Hernandez-Orallo, Jose & Modroiu, R. (2009). An Experimental Comparison of Performance Measures for Classification. Pattern Recognition Letters. 30. 27-38.

[PD2000]

Provost, F., Domingos, P. (2000). Well-trained PETs: Improving probability estimation trees (Section 6.2), CeDER Working Paper #IS-00-04, Stern School of Business, New York University.

[F2006]

Fawcett, T., 2006. An introduction to ROC analysis. Pattern Recognition Letters, 27(8), pp. 861-874.

[F2001]

Fawcett, T., 2001. Using rule sets to maximize ROC performance In Data Mining, 2001. Proceedings IEEE International Conference, pp. 131-138.

3.4.4.16. 检测错误权衡(DET)#

det_curve函数计算检测错误权衡曲线(DET)曲线 [WikipediaDET2017]。引用维基百科:

“检测错误权衡(DET)图是二元分类系统的错误率图形图,绘制了错误拒绝率与错误接受率。x轴和y轴通过它们的标准正态偏差(或仅通过对数变换)进行非线性缩放,产生比ROC曲线更线性的权衡曲线,并使用大部分图像区域来突出显示关键操作区域中重要的差异。”

DET曲线是接收者操作特征(ROC)曲线的变体,其中误负率绘制在y轴上而不是真阳性率上。DET曲线通常通过\(\phi^{-1}\)变换(其中\(\phi\)是累积分布函数)以标准正态偏差尺度绘制。由此产生的性能曲线明确地可视化了给定分类算法的错误类型的权衡。参见[Martin1997],了解示例和进一步的动机。

此图比较了两个示例分类器在同一分类任务上的ROC和DET曲线。

../_images/sphx_glr_plot_det_001.png
属性#
  • 如果检测分数服从正态分布(或接近正态分布),则DET曲线在正态偏差尺度上形成一条线性曲线。 [Navratil2007]指出,反之则不必然成立,甚至更一般的分布也能产生线性DET曲线。

  • 正态偏差尺度变换会分散这些点,从而占据相对更大的绘图空间。因此,在DET图上,具有相似分类性能的曲线可能更容易区分。

  • 由于假阴性率与真阳性率呈“反比”,因此DET曲线的完美点是原点(与ROC曲线的左上角相反)。

应用和局限性#

DET曲线直观易读,因此可以快速直观地评估分类器的性能。此外,DET曲线还可以用于阈值分析和工作点的选择。如果需要比较错误类型,这尤其有用。

另一方面,DET曲线不以单个数字提供其度量值。因此,对于自动化评估或与其他分类任务的度量值(如ROC曲线下的导出面积)的比较,可能更适合。

示例

参考文献

[WikipediaDET2017]

维基百科贡献者。检测误差权衡。维基百科,自由的百科全书。2017年9月4日,23:33 UTC。网址: https://en.wikipedia.org/w/index.php?title=Detection_error_tradeoff&oldid=798982054。访问日期:2018年2月19日。

[Martin1997]

A. Martin, G. Doddington, T. Kamm, M. Ordowski和M. Przybocki,检测任务性能评估中的DET曲线,NIST 1997。

3.4.4.17. 零一损失#

zero_one_loss 函数计算\(n_{\text{samples}}\)上的0-1分类损失(\(L_{0-1}\)) 的总和或平均值。默认情况下,该函数对样本进行归一化。要获取\(L_{0-1}\)的总和,请将normalize设置为False

在多标签分类中,如果其标签与预测严格匹配,则zero_one_loss将子集评分为1;如果存在任何错误,则评分为0。默认情况下,该函数返回不完美预测子集的百分比。要改为获取此类子集的数量,请将normalize设置为False

如果\(\hat{y}_i\)是第\(i\)个样本的预测值,而\(y_i\)是相应的真实值,则0-1损失\(L_{0-1}\)定义为

\[L_{0-1}(y, \hat{y}) = \frac{1}{n_\text{samples}} \sum_{i=0}^{n_\text{samples}-1} 1(\hat{y}_i \not= y_i)\]

其中\(1(x)\)指示函数。零一损失也可以计算为\(zero-one loss = 1 - accuracy\)

>>> from sklearn.metrics import zero_one_loss
>>> y_pred = [1, 2, 3, 4]
>>> y_true = [2, 2, 3, 4]
>>> zero_one_loss(y_true, y_pred)
0.25
>>> zero_one_loss(y_true, y_pred, normalize=False)
1.0

在具有二元标签指示符的多标签情况下,其中第一个标签集[0,1]存在错误

>>> zero_one_loss(np.array([[0, 1], [1, 1]]), np.ones((2, 2)))
0.5

>>> zero_one_loss(np.array([[0, 1], [1, 1]]), np.ones((2, 2)),  normalize=False)
1.0

示例

3.4.4.18. Brier评分损失#

brier_score_loss 函数计算二元类的Brier评分 [Brier1950]。引用维基百科:

“Brier评分是一个适当的评分函数,用于衡量概率预测的准确性。它适用于预测必须为一组互斥离散结果分配概率的任务。”

此函数返回实际结果\(y \in \{0,1\}\)与预测概率估计\(p = \operatorname{Pr}(y = 1)\)predict_proba)的均方误差,后者由以下公式输出:

\[BS = \frac{1}{n_{\text{samples}}} \sum_{i=0}^{n_{\text{samples}} - 1}(y_i - p_i)^2\]

Brier评分损失也在0到1之间,值越低(均方差越小),预测越准确。

这是一个关于此函数用法的小例子

>>> import numpy as np
>>> from sklearn.metrics import brier_score_loss
>>> y_true = np.array([0, 1, 1, 0])
>>> y_true_categorical = np.array(["spam", "ham", "ham", "spam"])
>>> y_prob = np.array([0.1, 0.9, 0.8, 0.4])
>>> y_pred = np.array([0, 1, 1, 0])
>>> brier_score_loss(y_true, y_prob)
0.055
>>> brier_score_loss(y_true, 1 - y_prob, pos_label=0)
0.055
>>> brier_score_loss(y_true_categorical, y_prob, pos_label="ham")
0.055
>>> brier_score_loss(y_true, y_prob > 0.5)
0.0

Brier评分可用于评估分类器的校准程度。但是,较低的Brier评分损失并不总是意味着更好的校准。这是因为,通过与均方误差的偏差-方差分解的类比,Brier评分损失可以分解为校准损失和细化损失的总和 [Bella2012]。校准损失定义为从ROC线段斜率导出的经验概率的均方差。细化损失可以定义为根据最佳成本曲线下的面积测量的预期最佳损失。细化损失可以独立于校准损失发生变化,因此较低的Brier评分损失并不一定意味着更好的校准模型。“只有当细化损失保持不变时,较低的Brier评分损失才总是意味着更好的校准” [Bella2012][Flach2008]

示例

参考文献

[Brier1950]

G. Brier, 用概率表示的预报验证,《月度天气评论》78.1 (1950)

[Bella2012] (1,2)

Bella, Ferri, Hernández-Orallo和Ramírez-Quintana,《机器学习模型的校准》载于Khosrow-Pour, M. “机器学习:概念、方法、工具和应用”。宾夕法尼亚州赫尔希:信息科学参考 (2012)。

[Flach2008]

Flach, Peter和Edson Matsubara,《“关于分类、排序和概率估计”》。达格斯图尔研讨会论文集。达格斯图尔-莱布尼茨信息学中心 (2008)。

3.4.4.19. 类别似然比#

class_likelihood_ratios 函数计算二元类别的阳性和阴性似然比 \(LR_\pm\),这可以解释为如下所述的测试后优势比与测试前优势比的比率。因此,此指标不受类别流行度(阳性类别样本数除以样本总数)的影响,**可以跨人群进行推断,而不管是否存在类别不平衡。**

\(LR_\pm\)指标在以下情况下非常有用:用于学习和评估分类器的可用数据是具有近似平衡类别的研究人群(例如病例对照研究),而目标应用(即一般人群)的流行度非常低。

阳性似然比\(LR_+\)是分类器正确预测样本属于阳性类别的概率除以预测属于阴性类别的样本属于阳性类别的概率

\[LR_+ = \frac{\text{PR}(P+|T+)}{\text{PR}(P+|T-)}.\]

此处的符号指的是预测的(\(P\))或真实的(\(T\))标签,符号\(+\)\(-\)分别指阳性和阴性类别,例如\(P+\)代表“预测为阳性”。

类似地,阴性似然比\(LR_-\)是阳性类别样本被分类为属于阴性类别的概率除以阴性类别样本被正确分类的概率

\[LR_- = \frac{\text{PR}(P-|T+)}{\text{PR}(P-|T-)}.\]

对于高于机会水平的分类器,\(LR_+\)大于1,**越高越好**,而\(LR_-\)的范围为0到1,**越低越好**。\(LR_\pm\approx 1\)的值对应于机会水平。

请注意,概率与计数不同,例如\(\operatorname{PR}(P+|T+)\)不等于真阳性计数tp的数量(有关实际公式,请参阅维基百科页面)。

示例

不同流行度下的解释#

两个类别似然比都可以用优势比(测试前和测试后)来解释

\[\text{测试后优势比} = \text{似然比} \times \text{测试前优势比}.\]

优势比通常通过以下公式与概率相关联

\[\text{优势比} = \frac{\text{概率}}{1 - \text{概率}},\]

或者等效地

\[\text{概率} = \frac{\text{优势比}}{1 + \text{优势比}}.\]

在给定人群中,测试前概率由流行度给出。通过将优势比转换为概率,似然比可以转换为分类器预测前后真正属于任一类别的概率

\[\text{测试后优势比} = \text{似然比} \times \frac{\text{测试前概率}}{1 - \text{测试前概率}},\]
\[\text{测试后概率} = \frac{\text{测试后优势比}}{1 + \text{测试后优势比}}.\]
数学发散#

\(fp = 0\)时,阳性似然比未定义,这可以解释为分类器完美地识别阳性病例。如果\(fp = 0\)并且此外\(tp = 0\),则会导致零除以零。例如,当使用总是预测阴性类别的DummyClassifier时会发生这种情况,因此作为完美分类器的解释就丢失了。

\(tn = 0\)时,阴性似然比未定义。这种发散是无效的,因为\(LR_- > 1\)将表明在被分类为阴性后,样本属于阳性类别的优势比增加,就好像分类行为导致了阳性状态一样。这包括总是预测阳性类别的DummyClassifier的情况(即当\(tn=fn=0\)时)。

\(tp=fn=0\)时,两个类别似然比都未定义,这意味着测试集中不存在阳性类别的样本。在对高度不平衡的数据进行交叉验证时,也可能发生这种情况。

在所有上述情况下,class_likelihood_ratios 函数默认情况下会发出适当的警告消息并返回nan,以避免在交叉验证折叠上取平均值时出现污染。

有关class_likelihood_ratios 函数的详细演示,请参见下面的示例。

参考文献#

3.4.4.20. 分类的D²得分#

D²得分计算解释的偏差分数。它是R²的推广,其中平方误差被推广并替换为选择的分类偏差\(\text{dev}(y, \hat{y})\)(例如,对数损失)。D²是一种技能得分。其计算公式为

\[D^2(y, \hat{y}) = 1 - \frac{\text{dev}(y, \hat{y})}{\text{dev}(y, y_{\text{null}})} \,.\]

其中\(y_{\text{null}}\)是仅截距模型的最优预测(例如,在对数损失的情况下,y_true的每类比例)。

与R²一样,最佳分数为1.0,也可能为负值(因为模型可以任意差)。始终预测\(y_{\text{null}}\)而不考虑输入特征的常数模型的D²得分为0.0。

D2对数损失得分#

d2_log_loss_score函数实现了D²的特殊情况,其中使用了对数损失,参见对数损失,即

\[\text{dev}(y, \hat{y}) = \text{log_loss}(y, \hat{y}).\]

以下是一些d2_log_loss_score函数的用法示例

>>> from sklearn.metrics import d2_log_loss_score
>>> y_true = [1, 1, 2, 3]
>>> y_pred = [
...    [0.5, 0.25, 0.25],
...    [0.5, 0.25, 0.25],
...    [0.5, 0.25, 0.25],
...    [0.5, 0.25, 0.25],
... ]
>>> d2_log_loss_score(y_true, y_pred)
0.0
>>> y_true = [1, 2, 3]
>>> y_pred = [
...     [0.98, 0.01, 0.01],
...     [0.01, 0.98, 0.01],
...     [0.01, 0.01, 0.98],
... ]
>>> d2_log_loss_score(y_true, y_pred)
0.981...
>>> y_true = [1, 2, 3]
>>> y_pred = [
...     [0.1, 0.6, 0.3],
...     [0.1, 0.6, 0.3],
...     [0.4, 0.5, 0.1],
... ]
>>> d2_log_loss_score(y_true, y_pred)
-0.552...

3.4.5. 多标签排序指标#

在多标签学习中,每个样本可以具有与其关联的任意数量的真实标签。目标是为真实标签赋予更高的分数和更好的排名。

3.4.5.1. 覆盖误差#

coverage_error函数计算必须包含在最终预测中的标签的平均数量,以便预测所有真实标签。如果您想知道平均需要预测多少个得分最高的标签才能不遗漏任何真实标签,这将非常有用。因此,此指标的最佳值是真实标签的平均数量。

注意

我们的实现分数比Tsoumakas等人2010年给出的分数大1。这使其能够处理实例具有0个真实标签的退化情况。

形式上,给定真实标签的二元指标矩阵\(y \in \left\{0, 1\right\}^{n_\text{samples} \times n_\text{labels}}\)和与每个标签相关的分数\(\hat{f} \in \mathbb{R}^{n_\text{samples} \times n_\text{labels}}\),覆盖率定义为

\[coverage(y, \hat{f}) = \frac{1}{n_{\text{samples}}} \sum_{i=0}^{n_{\text{samples}} - 1} \max_{j:y_{ij} = 1} \text{rank}_{ij}\]

其中\(\text{rank}_{ij} = \left|\left\{k: \hat{f}_{ik} \geq \hat{f}_{ij} \right\}\right|\)。给定排名定义,y_scores中的联系通过给出本来应该分配给所有关联值的最高排名来打破。

这是一个关于此函数用法的小例子

>>> import numpy as np
>>> from sklearn.metrics import coverage_error
>>> y_true = np.array([[1, 0, 0], [0, 0, 1]])
>>> y_score = np.array([[0.75, 0.5, 1], [1, 0.2, 0.1]])
>>> coverage_error(y_true, y_score)
2.5

3.4.5.2. 标签排序平均精度#

label_ranking_average_precision_score函数实现标签排序平均精度 (LRAP)。此指标与average_precision_score函数相关,但基于标签排序的概念,而不是精度和召回率。

标签排序平均精度 (LRAP) 对样本进行平均,以回答以下问题:对于每个真实标签,排名较高的标签中真实标签的比例是多少?如果您能够为与每个样本关联的标签赋予更好的排名,则此性能指标将更高。获得的分数始终严格大于0,最佳值为1。如果每个样本只有一个相关标签,则标签排序平均精度等效于平均倒数排名

形式上,给定真实标签的二元指标矩阵\(y \in \left\{0, 1\right\}^{n_\text{samples} \times n_\text{labels}}\)和与每个标签相关的分数\(\hat{f} \in \mathbb{R}^{n_\text{samples} \times n_\text{labels}}\),平均精度定义为

\[LRAP(y, \hat{f}) = \frac{1}{n_{\text{samples}}} \sum_{i=0}^{n_{\text{samples}} - 1} \frac{1}{||y_i||_0} \sum_{j:y_{ij} = 1} \frac{|\mathcal{L}_{ij}|}{\text{rank}_{ij}}\]

其中\(\mathcal{L}_{ij} = \left\{k: y_{ik} = 1, \hat{f}_{ik} \geq \hat{f}_{ij} \right\}\)\(\text{rank}_{ij} = \left|\left\{k: \hat{f}_{ik} \geq \hat{f}_{ij} \right\}\right|\)\(|\cdot|\)计算集合的基数(即集合中的元素数量),而\(||\cdot||_0\)\(\ell_0\)“范数”(计算向量中非零元素的数量)。

这是一个关于此函数用法的小例子

>>> import numpy as np
>>> from sklearn.metrics import label_ranking_average_precision_score
>>> y_true = np.array([[1, 0, 0], [0, 0, 1]])
>>> y_score = np.array([[0.75, 0.5, 1], [1, 0.2, 0.1]])
>>> label_ranking_average_precision_score(y_true, y_score)
0.416...

3.4.5.3. 排名损失#

label_ranking_loss 函数计算排序损失,该损失对样本进行平均,计算错误排序的标签对的数量,即真标签的分数低于假标签的分数,并根据假标签和真标签的有序对数的倒数进行加权。可达到的最低排序损失为零。

形式上,给定地面实况标签的二元指示矩阵\(y \in \left\{0, 1\right\}^{n_\text{samples} \times n_\text{labels}}\)和与每个标签相关的分数\(\hat{f} \in \mathbb{R}^{n_\text{samples} \times n_\text{labels}}\),排序损失定义为

\[ranking\_loss(y, \hat{f}) = \frac{1}{n_{\text{samples}}} \sum_{i=0}^{n_{\text{samples}} - 1} \frac{1}{||y_i||_0(n_\text{labels} - ||y_i||_0)} \left|\left\{(k, l): \hat{f}_{ik} \leq \hat{f}_{il}, y_{ik} = 1, y_{il} = 0 \right\}\right|\]

其中\(|\cdot|\)计算集合的基数(即集合中元素的数量),而\(||\cdot||_0\)\(\ell_0\)“范数”(计算向量中非零元素的数量)。

这是一个关于此函数用法的小例子

>>> import numpy as np
>>> from sklearn.metrics import label_ranking_loss
>>> y_true = np.array([[1, 0, 0], [0, 0, 1]])
>>> y_score = np.array([[0.75, 0.5, 1], [1, 0.2, 0.1]])
>>> label_ranking_loss(y_true, y_score)
0.75...
>>> # With the following prediction, we have perfect and minimal loss
>>> y_score = np.array([[1.0, 0.1, 0.2], [0.1, 0.2, 0.9]])
>>> label_ranking_loss(y_true, y_score)
0.0
参考文献#
  • Tsoumakas, G., Katakis, I., & Vlahavas, I. (2010). Mining multi-label data. In Data mining and knowledge discovery handbook (pp. 667-685). Springer US.

3.4.5.4. 归一化折损累积增益#

折损累积增益 (DCG) 和归一化折损累积增益 (NDCG) 是在 dcg_scorendcg_score 中实现的排序指标;它们将预测顺序与地面实况分数(例如,答案与查询的相关性)进行比较。

来自维基百科关于折损累积增益的页面

“折损累积增益 (DCG) 是衡量排序质量的指标。在信息检索中,它通常用于衡量 Web 搜索引擎算法或相关应用程序的有效性。使用搜索引擎结果集中的文档的等级相关性规模,DCG 基于文档在其结果列表中的位置来衡量文档的有用性或增益。增益从结果列表的顶部累积到底部,每个结果的增益在较低的排名中都会被折损。”

DCG 按预测顺序排列真实目标(例如,查询答案的相关性),然后将它们乘以对数衰减并对结果求和。可以在前 \(K\) 个结果后截断该和,在这种情况下,我们将其称为 DCG@K。NDCG 或 NDCG@K 是 DCG 除以通过完美预测获得的 DCG,因此它始终介于 0 和 1 之间。通常,NDCG 比 DCG 更受青睐。

与排序损失相比,NDCG 可以考虑相关性分数,而不是地面实况排序。因此,如果地面实况仅包含排序,则应优先使用排序损失;如果地面实况包含实际有用性分数(例如,不相关为 0,相关为 1,非常相关为 2),则可以使用 NDCG。

对于一个样本,给定每个目标的连续地面实况值的向量\(y \in \mathbb{R}^{M}\),其中\(M\)是输出的数量,以及预测\(\hat{y}\),它会诱导排序函数\(f\),DCG 分数为

\[\sum_{r=1}^{\min(K, M)}\frac{y_{f(r)}}{\log(1 + r)}\]

NDCG 分数是 DCG 分数除以针对\(y\)获得的 DCG 分数。

参考文献#
  • 维基百科关于折损累积增益的词条

  • Jarvelin, K., & Kekalainen, J. (2002). Cumulated gain-based evaluation of IR techniques. ACM Transactions on Information Systems (TOIS), 20(4), 422-446.

  • Wang, Y., Wang, L., Li, Y., He, D., Chen, W., & Liu, T. Y. (2013, May). A theoretical analysis of NDCG ranking measures. In Proceedings of the 26th Annual Conference on Learning Theory (COLT 2013)

  • McSherry, F., & Najork, M. (2008, March). Computing information retrieval performance measures efficiently in the presence of tied scores. In European conference on information retrieval (pp. 414-421). Springer, Berlin, Heidelberg.

3.4.6. 回归指标#

sklearn.metrics 模块实现了几种损失、分数和效用函数来衡量回归性能。其中一些已被增强以处理多输出情况:mean_squared_errormean_absolute_errorr2_scoreexplained_variance_scoremean_pinball_lossd2_pinball_scored2_absolute_error_score

这些函数具有一个multioutput关键字参数,用于指定如何平均每个单独目标的得分或损失。默认值为'uniform_average',它指定输出的均匀加权平均值。如果传递形状为(n_outputs,)ndarray,则其条目将被解释为权重,并返回相应的加权平均值。如果multioutput'raw_values',则所有未经修改的单个得分或损失都将以形状为(n_outputs,)的数组返回。

r2_scoreexplained_variance_score接受multioutput参数的附加值'variance_weighted'。此选项会导致每个单独分数的权重为相应目标变量的方差。此设置量化了全局捕获的未缩放方差。如果目标变量的尺度不同,则此分数更重视解释方差较大的变量。

3.4.6.1. R²得分,决定系数#

r2_score函数计算决定系数,通常表示为\(R^2\)

它表示模型中自变量解释的(y 的)方差比例。它提供了拟合优度的指标,因此也衡量了模型预测未见样本的可能性,通过解释方差的比例。

由于方差取决于数据集,因此\(R^2\)可能无法在不同的数据集中进行有意义的比较。最佳可能得分是 1.0,它可以为负数(因为模型可以任意变差)。始终预测 y 的预期(平均)值而忽略输入特征的常数模型将获得 0.0 的\(R^2\)得分。

注意:当预测残差的均值为零时,\(R^2\)得分和解释方差得分相同。

如果\(\hat{y}_i\)是第\(i\)个样本的预测值,而\(y_i\)是总共\(n\)个样本对应的真实值,则估计的\(R^2\)定义为

\[R^2(y, \hat{y}) = 1 - \frac{\sum_{i=1}^{n} (y_i - \hat{y}_i)^2}{\sum_{i=1}^{n} (y_i - \bar{y})^2}\]

其中\(\bar{y} = \frac{1}{n} \sum_{i=1}^{n} y_i\)\(\sum_{i=1}^{n} (y_i - \hat{y}_i)^2 = \sum_{i=1}^{n} \epsilon_i^2\)

请注意,r2_score计算未调整的\(R^2\),没有校正 y 样本方差的偏差。

在真实目标值为常数的特定情况下,\(R^2\)得分不是有限的:它是NaN(完美预测)或-Inf(不完美预测)。这种非有限得分可能会阻止网格搜索交叉验证等正确的模型优化正确执行。出于这个原因,r2_score的默认行为是用 1.0(完美预测)或 0.0(不完美预测)替换它们。如果force_finite设置为False,则此分数将回退到原始\(R^2\)定义。

这是一个r2_score函数使用的小示例

>>> from sklearn.metrics import r2_score
>>> y_true = [3, -0.5, 2, 7]
>>> y_pred = [2.5, 0.0, 2, 8]
>>> r2_score(y_true, y_pred)
0.948...
>>> y_true = [[0.5, 1], [-1, 1], [7, -6]]
>>> y_pred = [[0, 2], [-1, 2], [8, -5]]
>>> r2_score(y_true, y_pred, multioutput='variance_weighted')
0.938...
>>> y_true = [[0.5, 1], [-1, 1], [7, -6]]
>>> y_pred = [[0, 2], [-1, 2], [8, -5]]
>>> r2_score(y_true, y_pred, multioutput='uniform_average')
0.936...
>>> r2_score(y_true, y_pred, multioutput='raw_values')
array([0.965..., 0.908...])
>>> r2_score(y_true, y_pred, multioutput=[0.3, 0.7])
0.925...
>>> y_true = [-2, -2, -2]
>>> y_pred = [-2, -2, -2]
>>> r2_score(y_true, y_pred)
1.0
>>> r2_score(y_true, y_pred, force_finite=False)
nan
>>> y_true = [-2, -2, -2]
>>> y_pred = [-2, -2, -2 + 1e-8]
>>> r2_score(y_true, y_pred)
0.0
>>> r2_score(y_true, y_pred, force_finite=False)
-inf

示例

3.4.6.2. 平均绝对误差#

mean_absolute_error函数计算平均绝对误差,这是一种风险度量,对应于绝对误差损失或\(l1\)-范数损失的期望值。

如果\(\hat{y}_i\)是第\(i\)个样本的预测值,而\(y_i\)是对应的真实值,则在\(n_{\text{samples}}\)上估计的平均绝对误差 (MAE) 定义为

\[\text{MAE}(y, \hat{y}) = \frac{1}{n_{\text{samples}}} \sum_{i=0}^{n_{\text{samples}}-1} \left| y_i - \hat{y}_i \right|.\]

这是一个mean_absolute_error函数使用的小示例

>>> from sklearn.metrics import mean_absolute_error
>>> y_true = [3, -0.5, 2, 7]
>>> y_pred = [2.5, 0.0, 2, 8]
>>> mean_absolute_error(y_true, y_pred)
0.5
>>> y_true = [[0.5, 1], [-1, 1], [7, -6]]
>>> y_pred = [[0, 2], [-1, 2], [8, -5]]
>>> mean_absolute_error(y_true, y_pred)
0.75
>>> mean_absolute_error(y_true, y_pred, multioutput='raw_values')
array([0.5, 1. ])
>>> mean_absolute_error(y_true, y_pred, multioutput=[0.3, 0.7])
0.85...

3.4.6.3. 均方误差#

mean_squared_error函数计算均方误差,这是一种风险度量,对应于平方(二次)误差或损失的期望值。

如果\(\hat{y}_i\)是第\(i\)个样本的预测值,而\(y_i\)是对应的真实值,则在\(n_{\text{samples}}\)上估计的均方误差 (MSE) 定义为

\[\text{MSE}(y, \hat{y}) = \frac{1}{n_\text{samples}} \sum_{i=0}^{n_\text{samples} - 1} (y_i - \hat{y}_i)^2.\]

这是一个mean_squared_error函数使用的小示例

>>> from sklearn.metrics import mean_squared_error
>>> y_true = [3, -0.5, 2, 7]
>>> y_pred = [2.5, 0.0, 2, 8]
>>> mean_squared_error(y_true, y_pred)
0.375
>>> y_true = [[0.5, 1], [-1, 1], [7, -6]]
>>> y_pred = [[0, 2], [-1, 2], [8, -5]]
>>> mean_squared_error(y_true, y_pred)
0.7083...

示例

均方误差(MSE)的平方根称为均方根误差(RMSE),这是另一个常用的指标,其度量单位与目标变量相同。RMSE 可通过 root_mean_squared_error 函数获得。

3.4.6.4. 对数均方误差#

mean_squared_log_error 函数计算与对数平方误差或损失的期望值相对应的风险度量。

如果 \(\hat{y}_i\) 是第 \(i\) 个样本的预测值,而 \(y_i\) 是相应的真实值,则在 \(n_{\text{samples}}\) 上估计的对数均方误差 (MSLE) 定义为

\[\text{MSLE}(y, \hat{y}) = \frac{1}{n_\text{samples}} \sum_{i=0}^{n_\text{samples} - 1} (\log_e (1 + y_i) - \log_e (1 + \hat{y}_i) )^2.\]

其中 \(\log_e (x)\) 表示 \(x\) 的自然对数。当目标具有指数增长时,最好使用此度量,例如人口数量、某种商品多年的平均销售额等。请注意,此度量对预测不足的估计的惩罚大于对预测过度的估计。

下面是一个 mean_squared_log_error 函数使用的小示例

>>> from sklearn.metrics import mean_squared_log_error
>>> y_true = [3, 5, 2.5, 7]
>>> y_pred = [2.5, 5, 4, 8]
>>> mean_squared_log_error(y_true, y_pred)
0.039...
>>> y_true = [[0.5, 1], [1, 2], [7, 6]]
>>> y_pred = [[0.5, 2], [1, 2.5], [8, 8]]
>>> mean_squared_log_error(y_true, y_pred)
0.044...

均方根对数误差 (RMSLE) 可通过 root_mean_squared_log_error 函数获得。

3.4.6.5. 平均绝对百分比误差#

平均绝对百分比误差 (MAPE),也称为平均绝对百分比偏差 (MAPD),是回归问题的评估指标。此指标的思想是对相对误差敏感。例如,它不会因目标变量的全局缩放而改变。

如果 \(\hat{y}_i\) 是第 \(i\) 个样本的预测值,而 \(y_i\) 是相应的真实值,则在 \(n_{\text{samples}}\) 上估计的平均绝对百分比误差 (MAPE) 定义为

\[\text{MAPE}(y, \hat{y}) = \frac{1}{n_{\text{samples}}} \sum_{i=0}^{n_{\text{samples}}-1} \frac{{}\left| y_i - \hat{y}_i \right|}{\max(\epsilon, \left| y_i \right|)}\]

其中 \(\epsilon\) 是一个任意小的但严格为正的数,以避免当 y 为零时出现未定义的结果。

mean_absolute_percentage_error 函数支持多输出。

下面是一个 mean_absolute_percentage_error 函数使用的小示例

>>> from sklearn.metrics import mean_absolute_percentage_error
>>> y_true = [1, 10, 1e6]
>>> y_pred = [0.9, 15, 1.2e6]
>>> mean_absolute_percentage_error(y_true, y_pred)
0.2666...

在上例中,如果我们使用 mean_absolute_error,它将忽略小量值,只反映最高量值预测中的误差。但MAPE中解决了这个问题,因为它计算相对于实际输出的相对百分比误差。

注意

此处的 MAPE 公式并不代表常见的“百分比”定义:通过除以 100 将范围在 [0, 100] 内的百分比转换为范围在 [0, 1] 内的相对值。因此,200% 的误差对应于 2 的相对误差。这里的动机是拥有一个与 scikit-learn 中的其他误差度量(例如 accuracy_score)更一致的值范围。

要根据维基百科公式获得平均绝对百分比误差,请将此处计算的 mean_absolute_percentage_error 乘以 100。

参考文献#

3.4.6.6. 中位数绝对误差#

median_absolute_error 特别有趣,因为它对异常值具有鲁棒性。通过获取目标值和预测值之间所有绝对差值的中位数来计算损失。

如果 \(\hat{y}_i\) 是第 \(i\) 个样本的预测值,而 \(y_i\) 是相应的真实值,则在 \(n_{\text{samples}}\) 上估计的中位数绝对误差 (MedAE) 定义为

\[\text{MedAE}(y, \hat{y}) = \text{median}(\mid y_1 - \hat{y}_1 \mid, \ldots, \mid y_n - \hat{y}_n \mid).\]

median_absolute_error 不支持多输出。

下面是一个 median_absolute_error 函数使用的小示例

>>> from sklearn.metrics import median_absolute_error
>>> y_true = [3, -0.5, 2, 7]
>>> y_pred = [2.5, 0.0, 2, 8]
>>> median_absolute_error(y_true, y_pred)
0.5

3.4.6.7. 最大误差#

max_error 函数计算最大 残差,这是一个度量指标,用于捕捉预测值和真实值之间的最坏情况误差。在一个完美拟合的单输出回归模型中,max_error 在训练集上将为 0,尽管这在现实世界中极不可能,但此指标显示了模型拟合时的误差程度。

如果 \(\hat{y}_i\) 是第 \(i\) 个样本的预测值,而 \(y_i\) 是相应的真实值,则最大误差定义为

\[\text{Max Error}(y, \hat{y}) = \max(| y_i - \hat{y}_i |)\]

这是一个max_error函数使用的小例子。

>>> from sklearn.metrics import max_error
>>> y_true = [3, 2, 7, 1]
>>> y_pred = [9, 2, 7, 1]
>>> max_error(y_true, y_pred)
6

max_error不支持多输出。

3.4.6.8. 解释方差得分#

explained_variance_score计算解释方差回归得分

如果\(\hat{y}\)是估计的目标输出,\(y\)是对应的(正确)目标输出,\(Var\)方差(标准差的平方),则解释方差估计如下:

\[explained\_{}variance(y, \hat{y}) = 1 - \frac{Var\{ y - \hat{y}\}}{Var\{y\}}\]

最佳得分为1.0,较低的值表示较差的结果。

在真实目标值恒定的特殊情况下,解释方差得分不是有限的:它是NaN(完美预测)或-Inf(不完美预测)。这种非有限得分可能会阻止正确执行模型优化,例如网格搜索交叉验证。因此,explained_variance_score的默认行为是用1.0(完美预测)或0.0(不完美预测)替换它们。您可以将force_finite参数设置为False以防止此修复发生并回退到原始解释方差得分。

这是一个explained_variance_score函数使用的小例子。

>>> from sklearn.metrics import explained_variance_score
>>> y_true = [3, -0.5, 2, 7]
>>> y_pred = [2.5, 0.0, 2, 8]
>>> explained_variance_score(y_true, y_pred)
0.957...
>>> y_true = [[0.5, 1], [-1, 1], [7, -6]]
>>> y_pred = [[0, 2], [-1, 2], [8, -5]]
>>> explained_variance_score(y_true, y_pred, multioutput='raw_values')
array([0.967..., 1.        ])
>>> explained_variance_score(y_true, y_pred, multioutput=[0.3, 0.7])
0.990...
>>> y_true = [-2, -2, -2]
>>> y_pred = [-2, -2, -2]
>>> explained_variance_score(y_true, y_pred)
1.0
>>> explained_variance_score(y_true, y_pred, force_finite=False)
nan
>>> y_true = [-2, -2, -2]
>>> y_pred = [-2, -2, -2 + 1e-8]
>>> explained_variance_score(y_true, y_pred)
0.0
>>> explained_variance_score(y_true, y_pred, force_finite=False)
-inf

3.4.6.9. 泊松、伽马和Tweedie平均偏差#

mean_tweedie_deviance函数计算具有power参数(\(p\))的Tweedie平均偏差误差。这是一个引发回归目标预测期望值的指标。

存在以下特殊情况:

如果\(\hat{y}_i\)是第\(i\)个样本的预测值,\(y_i\)是对应的真实值,则在\(n_{\text{samples}}\)上估计的幂为\(p\)的Tweedie平均偏差误差(D)定义为:

\[\begin{split}\text{D}(y, \hat{y}) = \frac{1}{n_\text{samples}} \sum_{i=0}^{n_\text{samples} - 1} \begin{cases} (y_i-\hat{y}_i)^2, & \text{for }p=0\text{ (正态)}\\ 2(y_i \log(y_i/\hat{y}_i) + \hat{y}_i - y_i), & \text{for }p=1\text{ (泊松)}\\ 2(\log(\hat{y}_i/y_i) + y_i/\hat{y}_i - 1), & \text{for }p=2\text{ (伽马)}\\ 2\left(\frac{\max(y_i,0)^{2-p}}{(1-p)(2-p)}- \frac{y_i\,\hat{y}_i^{1-p}}{1-p}+\frac{\hat{y}_i^{2-p}}{2-p}\right), & \text{否则} \end{cases}\end{split}\]

Tweedie偏差是2-power次齐次函数。因此,power=2的伽马分布意味着同时缩放y_truey_pred对偏差没有影响。对于泊松分布power=1,偏差线性缩放;对于正态分布(power=0),则二次缩放。一般来说,power越高,赋予真实目标和预测目标之间极端偏差的权重越低。

例如,让我们比较两个预测值1.5和150,它们都比其对应的真实值大50%。

均方误差(power=0)对第二点的预测差异非常敏感。

>>> from sklearn.metrics import mean_tweedie_deviance
>>> mean_tweedie_deviance([1.0], [1.5], power=0)
0.25
>>> mean_tweedie_deviance([100.], [150.], power=0)
2500.0

如果我们将power增加到1,

>>> mean_tweedie_deviance([1.0], [1.5], power=1)
0.18...
>>> mean_tweedie_deviance([100.], [150.], power=1)
18.9...

误差差异减小。最后,通过设置power=2

>>> mean_tweedie_deviance([1.0], [1.5], power=2)
0.14...
>>> mean_tweedie_deviance([100.], [150.], power=2)
0.14...

我们将得到相同的误差。因此,当power=2时的偏差仅对相对误差敏感。

3.4.6.10. 分位数损失#

mean_pinball_loss函数用于评估分位数回归模型的预测性能。

\[\text{pinball}(y, \hat{y}) = \frac{1}{n_{\text{samples}}} \sum_{i=0}^{n_{\text{samples}}-1} \alpha \max(y_i - \hat{y}_i, 0) + (1 - \alpha) \max(\hat{y}_i - y_i, 0)\]

当分位数参数alpha设置为0.5时,分位数损失的值等同于mean_absolute_error的一半。

这是一个mean_pinball_loss函数使用的小例子。

>>> from sklearn.metrics import mean_pinball_loss
>>> y_true = [1, 2, 3]
>>> mean_pinball_loss(y_true, [0, 2, 3], alpha=0.1)
0.03...
>>> mean_pinball_loss(y_true, [1, 2, 4], alpha=0.1)
0.3...
>>> mean_pinball_loss(y_true, [0, 2, 3], alpha=0.9)
0.3...
>>> mean_pinball_loss(y_true, [1, 2, 4], alpha=0.9)
0.03...
>>> mean_pinball_loss(y_true, y_true, alpha=0.1)
0.0
>>> mean_pinball_loss(y_true, y_true, alpha=0.9)
0.0

可以使用特定的alpha值构建评分器对象。

>>> from sklearn.metrics import make_scorer
>>> mean_pinball_loss_95p = make_scorer(mean_pinball_loss, alpha=0.95)

此类评分器可用于通过交叉验证评估分位数回归器的泛化性能。

>>> from sklearn.datasets import make_regression
>>> from sklearn.model_selection import cross_val_score
>>> from sklearn.ensemble import GradientBoostingRegressor
>>>
>>> X, y = make_regression(n_samples=100, random_state=0)
>>> estimator = GradientBoostingRegressor(
...     loss="quantile",
...     alpha=0.95,
...     random_state=0,
... )
>>> cross_val_score(estimator, X, y, cv=5, scoring=mean_pinball_loss_95p)
array([13.6..., 9.7..., 23.3..., 9.5..., 10.4...])

还可以构建用于超参数调整的评分器对象。如以下链接示例中所述,必须切换损失的符号以确保更大意味着更好。

示例

  • 参见 梯度提升回归的预测区间,了解如何使用 pinball 损失来评估和调整在具有非对称噪声和异常值的数据上进行分位数回归模型的超参数的示例。

3.4.6.11. D² 分数#

D² 分数计算解释的偏差分数。它是 R² 的推广,其中平方误差被推广并替换为选择的偏差 \(\text{dev}(y, \hat{y})\)(例如,Tweedie、pinball 或平均绝对误差)。D² 是一种技能评分。其计算公式如下:

\[D^2(y, \hat{y}) = 1 - \frac{\text{dev}(y, \hat{y})}{\text{dev}(y, y_{\text{null}})} \,.\]

其中 \(y_{\text{null}}\) 是仅截距模型的最佳预测值(例如,对于 Tweedie 情形,y_true 的均值;对于绝对误差,为中位数;对于 pinball 损失,为 alpha 分位数)。

与R²一样,最佳分数为1.0,也可能为负值(因为模型可以任意差)。始终预测\(y_{\text{null}}\)而不考虑输入特征的常数模型的D²得分为0.0。

D² Tweedie 分数#

d2_tweedie_score 函数实现了 D² 的特例,其中 \(\text{dev}(y, \hat{y})\) 是 Tweedie 偏差,参见 泊松、伽马和 Tweedie 偏差的均值。它也称为 D² Tweedie,与 McFadden 的似然比指数相关。

参数 power 定义了 Tweedie 幂,与 mean_tweedie_deviance 中的一样。请注意,对于 power=0d2_tweedie_score 等于 r2_score(对于单个目标)。

可以使用以下方法构建具有特定 power 值的评分器对象:

>>> from sklearn.metrics import d2_tweedie_score, make_scorer
>>> d2_tweedie_score_15 = make_scorer(d2_tweedie_score, power=1.5)
D² pinball 分数#

d2_pinball_score 函数实现了使用 pinball 损失的 D² 特例,参见 Pinball 损失,即:

\[\text{dev}(y, \hat{y}) = \text{pinball}(y, \hat{y}).\]

参数 alpha 定义了 pinball 损失的斜率,与 mean_pinball_loss (Pinball 损失) 中的一样。它决定了 pinball 损失和 D² 最优的分位数级别 alpha。请注意,对于 alpha=0.5(默认值),d2_pinball_score 等于 d2_absolute_error_score

可以使用以下方法构建具有特定 alpha 值的评分器对象:

>>> from sklearn.metrics import d2_pinball_score, make_scorer
>>> d2_pinball_score_08 = make_scorer(d2_pinball_score, alpha=0.8)
D² 绝对误差分数#

d2_absolute_error_score 函数实现了 平均绝对误差 的特例:

\[\text{dev}(y, \hat{y}) = \text{MAE}(y, \hat{y}).\]

以下是一些 d2_absolute_error_score 函数的用法示例。

>>> from sklearn.metrics import d2_absolute_error_score
>>> y_true = [3, -0.5, 2, 7]
>>> y_pred = [2.5, 0.0, 2, 8]
>>> d2_absolute_error_score(y_true, y_pred)
0.764...
>>> y_true = [1, 2, 3]
>>> y_pred = [1, 2, 3]
>>> d2_absolute_error_score(y_true, y_pred)
1.0
>>> y_true = [1, 2, 3]
>>> y_pred = [2, 2, 2]
>>> d2_absolute_error_score(y_true, y_pred)
0.0

3.4.6.12. 回归模型的可视化评估#

在评估回归模型质量的方法中,scikit-learn 提供了 PredictionErrorDisplay 类。它允许以两种不同的方式直观地检查模型的预测误差。

../_images/sphx_glr_plot_cv_predict_001.png

左边的图显示了实际值与预测值的对比。对于旨在预测 y 的(条件)期望值的无噪声回归任务,完美的回归模型将显示在由预测值等于实际值定义的对角线上。离这条最优线越远,模型的误差就越大。在更现实的具有不可约噪声的环境中,也就是说,当 y 的所有变化都不能由 X 中的特征解释时,最佳模型将导致点云密集地排列在对角线周围。

请注意,上述情况仅在预测值为给定 Xy 的期望值时才成立。对于最小化均方误差目标函数或更一般地最小化其“幂”参数的任何值的 Tweedie 偏差均值 的回归模型,通常就是这样。

当绘制预测给定 Xy 的分位数的估计器的预测值时,例如 QuantileRegressor 或任何其他最小化 pinball 损失 的模型,一部分点预计会位于对角线上方或下方,具体取决于估计的分位数水平。

总而言之,虽然这种图直观易懂,但它并没有真正告诉我们如何获得更好的模型。

右侧图显示了残差(即实际值和预测值之间的差值)与预测值的关系。

此图使我们更容易直观地判断残差是否遵循同方差或异方差分布。

特别是,如果y|X的真实分布是泊松分布或伽马分布,则预期最佳模型的残差方差会随着E[y|X]的预测值增长(对于泊松分布是线性增长,对于伽马分布是二次增长)。

当拟合线性最小二乘回归模型(参见LinearRegressionRidge)时,我们可以使用此图来检查是否满足某些模型假设,特别是残差应不相关,其期望值应为零,且其方差应为常数(同方差)。

如果不是这种情况,特别是如果残差图显示某种香蕉形结构,这暗示模型可能存在错误指定,并且可能需要非线性特征工程或切换到非线性回归模型。

请参考下面的示例,了解利用此显示进行模型评估的方法。

示例

3.4.7. 聚类指标#

sklearn.metrics模块实现了几种损失函数、评分函数和效用函数来衡量聚类性能。有关更多信息,请参见聚类性能评估(例如聚类)部分和双聚类评估(对于双聚类)部分。

3.4.8. 虚拟估计器#

在进行监督学习时,一个简单的健全性检查包括将估计器与简单的经验法则进行比较。DummyClassifier实现了用于分类的几种此类简单策略。

  • stratified通过遵守训练集类别分布来生成随机预测。

  • most_frequent始终预测训练集中最频繁的标签。

  • prior始终预测最大化类别先验的类别(类似于most_frequent),而predict_proba返回类别先验。

  • uniform随机生成预测。

  • constant始终预测用户提供的常量标签。

    这种方法的主要动机是F1评分,当正类属于少数类时。

请注意,使用所有这些策略时,predict方法完全忽略输入数据!

为了说明DummyClassifier,首先让我们创建一个不平衡的数据集。

>>> from sklearn.datasets import load_iris
>>> from sklearn.model_selection import train_test_split
>>> X, y = load_iris(return_X_y=True)
>>> y[y != 1] = -1
>>> X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

接下来,让我们比较SVCmost_frequent的准确性。

>>> from sklearn.dummy import DummyClassifier
>>> from sklearn.svm import SVC
>>> clf = SVC(kernel='linear', C=1).fit(X_train, y_train)
>>> clf.score(X_test, y_test)
0.63...
>>> clf = DummyClassifier(strategy='most_frequent', random_state=0)
>>> clf.fit(X_train, y_train)
DummyClassifier(random_state=0, strategy='most_frequent')
>>> clf.score(X_test, y_test)
0.57...

我们看到SVC的性能并没有比虚拟分类器好多少。现在,让我们更改内核。

>>> clf = SVC(kernel='rbf', C=1).fit(X_train, y_train)
>>> clf.score(X_test, y_test)
0.94...

我们看到准确率提高到几乎100%。如果计算成本不高,建议采用交叉验证策略来更好地估计准确率。有关更多信息,请参见交叉验证:评估估计器性能部分。此外,如果您想在参数空间中进行优化,强烈建议使用适当的方法;有关详细信息,请参见调整估计器的超参数部分。

更一般地说,当分类器的准确率太接近随机时,这可能意味着出现了一些问题:特征无用、超参数未正确调整、分类器受到类别不平衡的影响等。

DummyRegressor还实现了四种简单的回归经验法则。

  • mean始终预测训练目标的平均值。

  • median始终预测训练目标的中位数。

  • quantile始终预测用户提供的训练目标的分位数。

  • constant始终预测用户提供的常数值。

在所有这些策略中,predict方法完全忽略输入数据。