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

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

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

另请参阅

对于样本之间的“成对”指标,而不是估计器或预测,请参见 成对指标、亲和力和核函数 部分。

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

使用 model_selection.GridSearchCVmodel_selection.cross_val_score 等工具进行模型选择和评估,需要一个 scoring 参数来控制它们应用于评估的估计器的指标。

3.4.1.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

‘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.1.2. 从指标函数定义评分策略#

以下指标函数未实现为命名评分器,有时是因为它们需要额外的参数,例如 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;请参阅下面的参数描述)。

自定义评分器对象#

第二个用例是使用 make_scorer 从一个简单的 python 函数构建一个完全自定义的评分器对象,它可以接受多个参数

  • 您要使用的 python 函数(在下面的示例中为 my_custom_loss_func

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

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

  • 任何其他参数,例如 f1_score 中的 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...

3.4.1.3. 实现您自己的评分对象#

您可以通过从头开始构建自己的评分对象来生成更灵活的模型评分器,而无需使用 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.1.4. 使用多个指标评估#

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.2. 分类指标#

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's 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.2.1. 从二元到多类和多标签#

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

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

  • "macro" 只是计算二元指标的平均值,对每个类别赋予相同的权重。在不常见类别仍然很重要的问题中,宏观平均可能是一种突出显示其性能的方法。另一方面,所有类别都同等重要的假设通常是不正确的,因此宏观平均会过度强调通常在不常见类别上的低性能。

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

  • "micro" 使每个样本类别对对总体指标贡献相等(除了 sample_weight 的结果)。这种方法不是对每个类别的指标求和,而是对构成每个类别指标的被除数和除数求和,以计算总体商。在多标签设置中可能更喜欢微观平均,包括多类分类,其中要忽略多数类别。

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

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

虽然多类数据以类标签数组的形式提供给指标,类似于二元目标,但多标签数据被指定为指示矩阵,其中单元格 [i, j] 的值为 1 表示样本 i 具有标签 j,否则为 0。

3.4.2.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.2.3. Top-k 准确率得分#

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

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

如果 \(\hat{f}_{i,j}\) 是对应于第 \(j\) 个最大预测分数的第 \(i\) 个样本的预测类别,而 \(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.2.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 statistic* 或 *信息量*。

注意

这里的多类定义似乎是二元分类中使用的指标最合理的扩展,尽管文献中没有明确的共识

  • 我们的定义:[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.2.5. Cohen’s kappa#

cohen_kappa_score 函数计算 Cohen’s kappa 统计量。该指标旨在比较不同人类标注者的标注,而不是比较分类器与真实情况。

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

kappa 得分可以针对二元或多类问题进行计算,但不能针对多标签问题进行计算(除非手动计算每个标签的得分),也不能针对超过两个标注者进行计算。

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

3.4.2.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.2.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.2.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.2.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 年。

[Davis2006]

J. Davis、M. Goadrich,精确率-召回率曲线与 ROC 曲线之间的关系,ICML 2006 年。

[Flach2015]

P.A. Flach、M. Kull,精确率-召回率增益曲线:PR 分析做对了,NIPS 2015 年。

3.4.2.9.1. 二元分类#

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

实际类别(观察)

预测类别(预期)

tp(真阳性)正确结果

fp(假阳性)意外结果

fn(假阴性)缺失结果

tn(真阴性)正确缺失结果

在这种情况下,我们可以定义精确率和召回率的概念

\[\text{precision} = \frac{\text{tp}}{\text{tp} + \text{fp}},\]
\[\text{recall} = \frac{\text{tp}}{\text{tp} + \text{fn}},\]

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

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

\[F_\beta = (1 + \beta^2) \frac{\text{precision} \times \text{recall}}{\beta^2 \text{precision} + \text{recall}}\]

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

\[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.2.9.2. 多类别和多标签分类#

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

请注意,在平均时,以下行为:

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

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

  • F-measure 的“宏观”平均被计算为每个标签/类 F-measure 的算术平均值,而不是算术精确率和召回率平均值的调和平均值。这两种计算方法在文献中都有出现,但并不等效,有关详细信息,请参见 [OB2019]

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

  • \(y\)真实 \((sample, label)\) 对的集合

  • \(\hat{y}\)预测 \((sample, label)\) 对的集合

  • \(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_beta

"微观"

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

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

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

"样本"

\(\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)\)

"宏观"

\(\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)\)

"加权"

\(\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.2.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...

在 2D 比较情况下(例如,图像相似性)

>>> 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.2.11. 铰链损失#

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

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

\[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.2.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))\]

这可以扩展到多类情况。令一组样本的真实标签被编码为一个 1-of-K 二进制指示矩阵 \(Y\),即 \(y_{i,k} = 1\) 如果样本 \(i\) 的标签为 \(k\),来自一组 \(K\) 个标签。令 \(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\}\) 的内部求和得到二元对数损失。

The 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] 表示第一个样本有 90% 的概率属于标签 0。对数损失是非负的。

3.4.2.13. 马修斯相关系数#

The 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...

3.4.2.14. 多标签混淆矩阵#

The 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.2.15. 受试者工作特征 (ROC)#

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

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

此函数需要真二元值和目标分数,目标分数可以是正类的概率估计、置信值或二元决策。以下是如何使用 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.2.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.2.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'。除了 'macro' [F2006]'weighted' [F2001] 平均之外,OvR 还支持 'micro' 平均。

在假阳性率不可容忍的应用中,可以使用 roc_auc_score 的参数 max_fpr 将 ROC 曲线概括到给定限制。

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

../_images/sphx_glr_plot_roc_002.png

3.4.2.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. 和 Till, R.J.,(2001)。多类分类问题中 ROC 曲线下面积的简单推广。 机器学习,45(2),第 171-186 页。

[FC2009]

Ferri, Cèsar & Hernandez-Orallo, Jose & Modroiu, R. (2009)。分类性能度量实验比较。 模式识别快报。30. 27-38。

[PD2000]

Provost, F.,Domingos, P. (2000)。训练有素的宠物:改进概率估计树(第 6.2 节),CeDER 工作文件 #IS-00-04,纽约大学斯特恩商学院。

[F2006]

Fawcett, T.,2006。 ROC 分析简介。 模式识别快报,27(8),第 861-874 页。

[F2001]

Fawcett, T.,2001。 使用规则集最大化 ROC 性能 数据挖掘,2001。IEEE 国际会议论文集,第 131-138 页。

3.4.2.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.2.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)\)指示函数。0-1 损失也可以计算为 \(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.2.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.2.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.2.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}}\) 的常数模型,不考虑输入特征,将获得 0.0 的 D² 分数。

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.3. 多标签排序指标#

在多标签学习中,每个样本可以与任意数量的真实标签相关联。目标是为真实标签赋予高分并进行更好的排序。

3.4.3.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.3.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.3.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)。挖掘多标签数据。在数据挖掘和知识发现手册中(第 667-685 页)。Springer 美国。

3.4.3.4. 归一化折现累积增益#

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

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

“折现累积增益 (DCG) 是衡量排名质量的指标。在信息检索中,它通常用于衡量网络搜索引擎算法或相关应用程序的有效性。使用搜索引擎结果集中文档的等级相关性尺度,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)。基于累积增益的信息检索技术评估。ACM 信息系统汇刊 (TOIS),20(4),422-446。

  • Wang, Y.,Wang, L.,Li, Y.,He, D.,Chen, W. 和 Liu, T. Y. (2013 年 5 月)。NDCG 排名指标的理论分析。在第 26 届年度学习理论会议 (COLT 2013) 论文集中

  • McSherry, F. 和 Najork, M. (2008 年 3 月)。在存在绑定分数的情况下有效地计算信息检索性能指标。在欧洲信息检索会议 (第 414-421 页) 中。Springer,柏林,海德堡。

3.4.4. 回归指标#

模块 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 接受一个额外的值 'variance_weighted' 用于 multioutput 参数。此选项会导致每个单独分数按相应目标变量的方差加权。此设置量化了全局捕获的未缩放方差。如果目标变量具有不同的比例,则此分数会更加重视解释方差较高的变量。

3.4.4.1. R² 分数,决定系数#

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

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

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

注意:当预测残差的平均值为零时,\(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.4.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.4.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),是另一个常见的度量,它提供了与目标变量相同的单位的度量。RSME 可通过 root_mean_squared_error 函数获得。

3.4.4.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.4.5. 平均绝对百分比误差#

mean_absolute_percentage_error (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 中得到了解决,因为它计算的是相对于实际输出的相对百分比误差。

3.4.4.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.4.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.4.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.4.9. 平均泊松、伽马和 Tweedie 偏差#

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

以下特殊情况存在,

如果 \(\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{ (Normal)}\\ 2(y_i \log(y_i/\hat{y}_i) + \hat{y}_i - y_i), & \text{for }p=1\text{ (Poisson)}\\ 2(\log(\hat{y}_i/y_i) + y_i/\hat{y}_i - 1), & \text{for }p=2\text{ (Gamma)}\\ 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{otherwise} \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.4.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...])

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

示例

  • 请参阅 梯度提升回归的预测区间,了解如何使用弹球损失来评估和调整具有非对称噪声和异常值的数据的分位数回归模型的超参数。

3.4.4.11. D² 分数#

D² 分数计算解释的偏差分数。它是 R² 的推广,其中平方误差被推广并用选择的偏差 \(\text{dev}(y, \hat{y})\)(例如,Tweedie、弹球或平均绝对误差)替换。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 的平均值,对于绝对误差,中位数,对于弹球损失,alpha 分位数)。

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

D² Tweedie score#

The d2_tweedie_score function implements the special case of D² where \(\text{dev}(y, \hat{y})\) is the Tweedie deviance, see Mean Poisson, Gamma, and Tweedie deviances. It is also known as D² Tweedie and is related to McFadden’s likelihood ratio index.

The argument power defines the Tweedie power as for mean_tweedie_deviance. Note that for power=0, d2_tweedie_score equals r2_score (for single targets).

A scorer object with a specific choice of power can be built by:

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

The d2_pinball_score function implements the special case of D² with the pinball loss, see Pinball loss, i.e.:

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

The argument alpha defines the slope of the pinball loss as for mean_pinball_loss (Pinball loss). It determines the quantile level alpha for which the pinball loss and also D² are optimal. Note that for alpha=0.5 (the default) d2_pinball_score equals d2_absolute_error_score.

A scorer object with a specific choice of alpha can be built by:

>>> from sklearn.metrics import d2_pinball_score, make_scorer
>>> d2_pinball_score_08 = make_scorer(d2_pinball_score, alpha=0.8)
D² absolute error score#

The d2_absolute_error_score function implements the special case of the Mean absolute error:

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

Here are some usage examples of the d2_absolute_error_score function:

>>> 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.4.12. 回归模型的视觉评估#

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

../_images/sphx_glr_plot_cv_predict_001.png

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

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

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

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

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

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

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

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

如果不是这种情况,特别是如果残差图显示出一些香蕉形结构,这表明模型可能被错误指定,并且非线性特征工程或切换到非线性回归模型可能会有用。

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

示例

3.4.5. 聚类指标#

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

3.4.6. 虚拟估计器#

在进行监督学习时,一个简单的健全性检查包括将自己的估计器与简单的经验法则进行比较。 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 方法完全忽略了输入数据。