sklearn中分类模型评估指标(三):精确率、召回率、F值

这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战

简述

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

而F值( F 1 F_1 F β F_{\beta} 值)则可以解释为精确率和召回率的加权调和平均值。

F β F_{\beta} 值的取值范围为[0,1],在1处表示模型效果最好,在0处表示模型效果最差。

β = 1 \beta =1 时, F 1 F_1 F β F_{\beta} 等价,表示精确率和召回率同等重要。

关于精确率、召回率和F值的详细内容,请参考我的另一篇博文:十分钟掌握分类算法的评估指标

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

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

AP = n ( R n R n 1 ) P n \text{AP} = \sum_n (R_n - R_{n-1}) P_n

其中, P n P_n R n R_n 是第 n 个阈值的准确率和召回率。

这种实现是没有插值的,不同于用梯形规则计算precision-recall曲线下的面积,后者使用线性插值,可能过于乐观。

注意:此实现仅限于二分类任务或多标签分类任务。

以下几个函数允许您计算精确率、召回率和F值分数:

函数 说明
average_precision_score(y_true, y_score, *) 根据预测分数计算平均精确率 (AP)
f1_score(y_true, y_pred, *[, labels, …]) 计算F1值
fbeta_score(y_true, y_pred, *, beta[, …]) 计算F-beta值
precision_recall_curve(y_true, probas_pred, *) 计算不同概率阈值下的精确率召回率对
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函数仅适用于二分类和多标签分类场景。

二分类场景

在二分类任务中,术语“正”和“负”是指分类器的预测,术语“真”和“假”是指该预测结果是否对应于外部(实际值)判断, 鉴于这些定义,我们可以制定下表:

image.png

在这种情况下,精确率、召回率和 F值的公式如下:

precision = t p t p + f p , \text{precision} = \frac{tp}{tp + fp},
recall = t p t p + f n , \text{recall} = \frac{tp}{tp + fn},
F β = ( 1 + β 2 ) precision × recall β 2 precision + recall . F_\beta = (1 + \beta^2) \frac{\text{precision} \times \text{recall}}{\beta^2 \text{precision} + \text{recall}}.

示例代码:

from sklearn import metrics
import numpy as np
import pprint

y_pred = [0, 1, 0, 0]
y_true = [0, 1, 0, 1]

# average参数的默认值为binary, "binary"表示用于二分类
print(metrics.precision_score(y_true, y_pred))
print(metrics.precision_score(y_true, y_pred, average='binary'))

print(metrics.recall_score(y_true, y_pred))
print(metrics.recall_score(y_true, y_pred, average='binary'))

print(metrics.f1_score(y_true, y_pred))
print(metrics.f1_score(y_true, y_pred, average='binary'))


print(metrics.fbeta_score(y_true, y_pred, beta=0.5))

print(metrics.fbeta_score(y_true, y_pred, beta=1))

print(metrics.fbeta_score(y_true, y_pred, beta=2))
print("------------------")

pprint.pprint(metrics.precision_recall_fscore_support(y_true, y_pred, beta=0.5))
print("------------------")

y_true = np.array([0, 0, 1, 1])
y_scores = np.array([0.1, 0.4, 0.35, 0.8])

# PR曲线实则是以precision(精准率)和recall(召回率)这两个为变量而做出的曲线,其中recall为横坐标,precision为纵坐标。
# 设定一系列阈值,计算每个阈值对应的recall和precision,即可计算出PR曲线各个点。
precision, recall, threshold = metrics.precision_recall_curve(y_true, y_scores)
print("", precision, "\n",recall,"\n", threshold)
# 其中,y_true是正确标签,y_score是概率输出值,thresholds是阈值,
# 当y_score>=thresholds,则预测为正样本,当y_score<thresholds,则预测为负样本。
# 注意,输出的precision和recall最后一个值分别为1和0,并且没有对应的阈值。

# 该例子中,在实际的数据集中,正样本实际数量为2个,负样本实际数量为2个。

# 当index=0,thresholds[index]=0.35,此时预测的标签为[0,1,1,1],
# tp=2,fp=1,fn=0,所以precision=0.67,recall=1

# 当index=1,thresholds[index]=0.4,此时预测的标签为[0,1,0,1],
# tp=1,fp=1,fn=1,所以precision=0.5,recall=0.5

# 当index=2,thresholds[index]=0.8,此时预测的标签为[0,0,0,1],
# tp=1,fp=0,fn=1,所以precision=1,recall=0.5


print("------------------")
print(metrics.average_precision_score(y_true, y_scores))
复制代码

运行结果:

1.0
1.0
0.5
0.5
0.6666666666666666
0.6666666666666666
0.8333333333333334
0.6666666666666666
0.5555555555555556
------------------
(array([0.66666667, 1.        ]),
 array([1. , 0.5]),
 array([0.71428571, 0.83333333]),
 array([2, 2]))
------------------
 [0.66666667 0.5        1.         1.        ] 
 [1.  0.5 0.5 0. ] 
 [0.35 0.4  0.8 ]
------------------
0.8333333333333333
复制代码

多分类与多标签场景

在多分类和多标签分类任务中,精确率、召回率和F值的概念可以独立应用于每个标签。

这里有几种遍历标签组合结果方法,由average_precision_score(仅限多标签)、f1_scorefbeta_scoreprecision_recall_fscore_supportprecision_scorerecall_score函数的average(平均)参数指定。 请注意,如果包含所有标签,则多类设置中的“微”平均将产生精度、召回率,并且这些都与准确度相同。 另请注意,“加权”平均可能会产生不在精度和召回率之间的 F 分数。

请注意:如果包含所有标签,则多分类场景中设置的“micro”平均,产生的精确率、召回率和F值,这些都与准确率相同。

同时也请注意:“weighted”平均可能会产生不在精度和召回率之间的F分数。

为了使这更加清晰,请参考以下符号:

  • y y 表示预测对 ( s a m p l e , l a b e l ) (sample, label) 的集合(分类器的预测值)
  • y ^ \hat{y} 表示真实对 ( s a m p l e , l a b e l ) (sample, label) 的集合(实际值)
  • L L 表示标签集
  • S S 表示样本集
  • y s y_s 表示 y y 的子集,样本 s s
  • y l y_l 表示 y y 的子集,标签 l l
  • 同样的, y ^ s \hat{y}_s y ^ l \hat{y}_l y ^ \hat{y} 的子集
  • P ( A , B ) : = A B A P(A, B) := \frac{\left| A \cap B \right|}{\left|A\right|} ,表示精确率,其中B为真实为正的集合,A为预测为正的集合
  • R ( A , B ) : = A B B R(A, B) := \frac{\left| A \cap B \right|}{\left|B\right|} ,表示召回率,其中B为真实为正的集合,A为预测为正的集合
  • F β ( A , B ) : = ( 1 + β 2 ) P ( A , B ) × R ( A , B ) β 2 P ( A , B ) + R ( A , B ) 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)}

指标定义如下表所示:

average参数 Precision Recall F_beta
"micro" P ( y , y ^ ) P(y, \hat{y}) R ( y , y ^ ) R(y, \hat{y}) F β ( y , y ^ ) F_\beta(y, \hat{y})
"samples" 1 S s S P ( y s , y ^ s ) \frac{1}{S} \sum_{s \in S} P(y_s, \hat{y}_s) 1 S s S R ( y s , y ^ s ) \frac{1}{S} \sum_{s \in S} R(y_s, \hat{y}_s) 1 S s S F β ( y s , y ^ s ) \frac{1}{S} \sum_{s \in S} F_\beta(y_s, \hat{y}_s)
"macro" 1 L l L P ( y l , y ^ l ) \frac{1}{L} \sum_{l \in L} P(y_l, \hat{y}_l) 1 L l L R ( y l , y ^ l ) \frac{1}{L} \sum_{l \in L} R(y_l, \hat{y}_l) 1 L l L F β ( y l , y ^ l ) \frac{1}{L} \sum_{l \in L} F_\beta(y_l, \hat{y}_l)
"weighted" 1 l L y ^ l l L y ^ l P ( y l , y ^ l ) \frac{1}{\sum_{l \in L} \hat{y}_l} \sum_{l \in L} \hat{y}_l P(y_l, \hat{y}_l) 1 l L y ^ l l L y ^ l R ( y l , y ^ l ) \frac{1}{\sum_{l \in L} \hat{y}_l} \sum_{l \in L} \hat{y}_l R(y_l, \hat{y}_l) 1 l L y ^ l l L y ^ l F β ( y l , y ^ l ) \frac{1}{\sum_{l \in L} \hat{y}_l} \sum_{l \in L} \hat{y}_l F_\beta(y_l, \hat{y}_l)
None P ( y l , y ^ l ) , l L \langle P(y_l, \hat{y}_l) , l \in L \rangle R ( y l , y ^ l ) , l L \langle R(y_l, \hat{y}_l), l \in L \rangle F β ( y l , y ^ l ) , l L \langle F_\beta(y_l, \hat{y}_l) , l \in L \rangle

备注:

关于分类评估指标(精确率、召回率和F值)的详细说明,请参考我的另一篇博客:十分钟掌握分类算法的评估指标

关于average参数的详细说明,请参考我的另一篇博客::sklearn中针对不同分类场景模型评估指标函数概述

示例代码:

from sklearn import metrics
import pprint

y_true = [0, 1, 2, 0, 1, 2]
y_pred = [0, 2, 1, 0, 0, 1]

print(metrics.precision_score(y_true, y_pred, average='macro'))
print(metrics.recall_score(y_true, y_pred, average='micro'))
print(metrics.f1_score(y_true, y_pred, average='weighted'))
print(metrics.fbeta_score(y_true, y_pred, average='macro', beta=0.5))
print("++++++++++++")

# 对于具有“负类”的多分类,可以排除一些标签:
# 比如,排除0之后,没有标签被正确召回的情况
print(metrics.recall_score(y_true, y_pred, labels=[1, 2], average='micro'))

# 数据样本中不存在的标签可能会在宏观平均中考虑在内。
print(metrics.precision_score(y_true, y_pred, labels=[0, 1, 2, 3], average='macro'))
print("------------")

# 计算精确率、召回率、F值、真实值数据集中每个标签的数量
pprint.pprint(metrics.precision_recall_fscore_support(y_true, y_pred, beta=0.5, average=None))
print("------------")

# 计算指定标签,每个标签的指标
print(metrics.precision_score(y_true, y_pred, average=None, labels=[0, 2]))
print(metrics.recall_score(y_true, y_pred, average=None, labels=[0, 2]))
print("------------")

# 计算所有标签,每个标签的指标
print(metrics.precision_score(y_true, y_pred, average=None))
print(metrics.recall_score(y_true, y_pred, average=None))
print("------------")

# 计算指定标签的宏平均
print(metrics.precision_score(y_true, y_pred, average='macro', labels=[0, 2]))
print(metrics.recall_score(y_true, y_pred, average='macro', labels=[0, 2]))

复制代码

运行结果:

0.2222222222222222
0.3333333333333333
0.26666666666666666
0.23809523809523805
++++++++++++
0.0
0.16666666666666666
------------
(array([0.66666667, 0.        , 0.        ]),
 array([1., 0., 0.]),
 array([0.71428571, 0.        , 0.        ]),
 array([2, 2, 2]))
------------
[0.66666667 0.        ]
[1. 0.]
------------
[0.66666667 0.         0.        ]
[1. 0. 0.]
------------
0.3333333333333333
0.5
复制代码

在多分类标签场景下,微平均的示例代码如下所示:

from sklearn import metrics
y_true = [0, 1, 2, 0, 4, 2, 3]
y_pred = [0, 1, 1, 0, 4, 1, 2]
print(metrics.recall_score(y_true, y_pred, average='micro'))
print(metrics.f1_score(y_true, y_pred, average='micro'))
print(metrics.precision_score(y_true, y_pred, average='micro'))
print(metrics.accuracy_score(y_true, y_pred))
复制代码

运行结果:

0.5714285714285714
0.5714285714285714
0.5714285714285714
0.5714285714285714
复制代码

总结

在二分类场景时,average参数为"binary"; 在多分类场景时,average参数通常为"micro","macro","weighted"; 在多标签分类场景时,average参数为"samples"。

参考文档

猜你喜欢

转载自juejin.im/post/7033800696369528862