准确率、精确率、召回率、F1-score

2020-03-02 14:38:44 浏览数 (3)

分类是机器学习中比较常见的任务,对于分类任务常见的评价指标有准确率(Accuracy)、精确率(Precision)、召回率(Recall)、F1 score、ROC曲线(Receiver Operating Characteristic Curve)等

这篇文章将结合sklearn对准确率、精确率、召回率、F1-score进行讲解

混淆矩阵

如上图所示,要了解各个评价指标,首先需要知道混淆矩阵,混淆矩阵中的P表示Positive,即正例或者阳性,N表示Negative,即负例或者阴性。你也可以把P和N分别理解为二分类中的1-0

  • TP:实际为正,预测为正的样本数量
  • FP:实际为负,预测为正的样本数量
  • FN:实际为正,预测为负的样本数量
  • TN:实际为负,预测为负的样本数量

另外

  • TP FP:表示所有预测为正的样本数量
  • TN FN:表示所有预测为负的样本数量
  • TP FN:表示实际为正的样本数量
  • TN FP:表示实际为负的样本数量

准确率

准确率是分类正确的样本占总样本个数,即

$$ accuracy = frac{n_{correct}}{n_{total}} $$

其中,$n_{correct}$表示被正确分类的样本个数,$n_{total}$表示样本总数

综合上面的混淆矩阵,公式还可以这样写

$$ accuracy=frac{TP TN}{TP TN FP FN} $$

准确率是分类问题中最简单最直观的评价指标,但存在明显的缺陷。比如正负样本的比例不均衡,假设样本中正样本占90%,负样本占10%,那分类器只需要一直预测为正,就可以得到90%的准确率,但其实际性能是非常低下的

下面看一下sklearn中计算准确率的示例

代码语言:javascript复制
import numpy as np
from sklearn.metrics import accuracy_score as accu

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

print(accu(y_true, y_pred)) # 0.5
print(accu(y_true, y_pred, normalize=False)) # 2
# normalize=False 返回分类正确的样本数量

# 在具有二元标签指示符的多标签分类问题中
print(accu(np.array([0, 1], [1, 1]), np.ones((2, 2)))) # 0.5

对于最后两行代码

$$ y_{true}=begin{bmatrix} {0}&{1}\ {1}&{1} end{bmatrix}, y_{pred}=begin{bmatrix} {1}&{1}\ {1}&{1} end{bmatrix} $$

矩阵的每一行表示一个样本,列表示标签(每个样本具有两个标签,这两个标签共同确定样本类别)。对于这种情况,此时实际上只有一个样本是预测正确的,因此准确率为0.5

精确率

精确率指模型预测为正的样本中实际也为正的样本 占 被预测为正的样本的比例。计算公式为

$$ precision=frac{TP}{TP FP} $$

代码如下

代码语言:javascript复制
from sklearn.metrics import precision_score as ps

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

print(ps(y_true, y_pred, average="macro"))    # 0.22222
print(ps(y_true, y_pred, average="micro"))    # 0.33333
print(ps(y_true, y_pred, average="weighted")) # 0.22222
print(ps(y_true, y_pred, average=None)) # [0.6666 0. 0.]

average的参数可选值有None, binary(默认), micro, macro, samples, weighted

上面的$y_{true}$有3个类别,分别为类0,类1,类2。我们将每个类别的TP、FP、FN列在下表中

类别

TP

FP

FN

0

2

1

0

1

0

2

2

2

0

1

1

那么每个类别的precision也就得到了

$$ begin{align*} P_0&=frac{2}{1 2}=frac{2}{3}approx 0.667\ P_1&=frac{0}{0 2}=0\ P_2&=frac{0}{0 1}=0 end{align*} $$

于是Macro Precision也就知道了,就是$frac{P_0 P_1 P_2}{3}approx 0.222$

Micro Precision的计算要从每个样本考虑,所有样本中预测正确的有两个,那么TP就是2,剩下的4个预测结果都可以看作FP,于是Micro Precision就是$frac{2}{2 4}=frac{1}{3}approx 0.333$

最后还有一个weighted,因为这里每个类别的数量恰好占比都是1/3,所以结果是

$$ P_w=frac{1}{3}*P_0 frac{1}{3}*P_1 frac{1}{3}*P_2approx 0.222 $$

  • 如果每个类别的样本数量不多,那么Macro和Micro没有太大差异
  • 如果每个类别的样本数量差异很大,那么注重样本量多的类时用Micro,注重样本量少的类时用Macro
  • 如果Macro>>Micro的值,那么检查样本量多的类来确定指标表现差的原因
  • 如果Micro>>Macro的值,那么检查样本量少的类来确定指标表现差的原因

召回率

召回率指实际为正的样本中,预测也为正的样本 占 实际为正的样本的比例。计算公式为

$$ recall=frac{TP}{TP FN} $$

代码如下

代码语言:javascript复制
from sklearn.metrics import recall_score as rs

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

print(rs(y_true, y_pred, average="macro")) # 0.3333
print(rs(y_true, y_pred, average="micro")) # 0.3333
print(rs(y_true, y_pred, average="weighted")) # 0.3333
print(rs(y_true, y_pred, average=None)) # [1. 0. 0.]

Recall和Precision只有计算公式不同,它们average参数的计算方式都是相同的,这里不再赘述

F1-score

F1-score是精确率和召回率的加权平均值,计算公式为

$$ F1-score=frac{2*precision*recall}{precision revall} $$

Precision体现了模型对负样本的区分能力,Precision越高,模型对负样本的区分能力越强

Recall体现了模型对正样本的识别能力,Recall越高,模型对正样本的识别能力越强

F1-score是两者的综合,F1-score越高,说明模型越稳健

代码如下

代码语言:javascript复制
from sklearn.metrics import f1_score as fs

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

print(fs(y_true, y_pred, average="macro")) # 0.2666
print(fs(y_true, y_pred, average="micro")) # 0.3333
print(fs(y_true, y_pred, average="weighted")) # 0.2666
print(fs(y_true, y_pred, averge=None)) # [0.8 0. 0.]

Worked Example

对于正常的邮件

$$ begin{align*} precision&=frac{16}{16 2}=frac{8}{9}\ Recall&=frac{16}{16 4}=frac{4}{5}\ F1-score&=frac{2*frac{8}{9}*0.8}{frac{8}{9} 0.8} = a end{align*} $$

对于垃圾邮件

$$ begin{align*} precision&=frac{3}{3 4}=frac{3}{7}\ Recall&=frac{3}{3 2}=frac{3}{5}\ F1-score&=frac{2*frac{3}{7}*0.6}{frac{3}{7} 0.6} = b end{align*} $$

对于整体的所有邮件

$$ begin{align*} P &= frac{frac{8}{9} frac{3}{7}}{2} \ R &= frac{0.8 0.6}{2}\ F1 &= frac{a b}{2} end{align*} $$

0 人点赞