分类是机器学习中比较常见的任务,对于分类任务常见的评价指标有准确率(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:表示实际为负的样本数量
准确率
准确率是分类正确的样本占总样本个数,即
$$ \text{accuracy} = \frac{n_{\text{correct}}}{n_{\text{total}}} $$
其中,$n_{\text{correct}}$表示被正确分类的样本个数,$n_{\text{total}}$表示样本总数
综合上面的混淆矩阵,公式还可以这样写
$$ \text{accuracy}=\frac{\text{TP}+\text{TN}}{\text{TP}+\text{TN}+\text{FP}+\text{FN}} $$
准确率是分类问题中最简单最直观的评价指标,但存在明显的缺陷。比如正负样本的比例不均衡,假设样本中正样本占90%,负样本占10%,那分类器只需要一直预测为正,就可以得到90%的准确率,但其实际性能是非常低下的
下面看一下sklearn中计算准确率的示例
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
精确率
精确率指模型预测为正的样本中实际也为正的样本 占 被预测为正的样本的比例。计算公式为
$$ \text{precision}=\frac{\text{TP}}{\text{TP}+\text{FP}} $$
代码如下
from sklearn.metrics import precision_score as ps
y_{\text{true}} = [0, 1, 2, 0, 1, 2]
y_{\text{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{aligned} 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{aligned} $$
于是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_2\approx 0.222 $$
- 如果每个类别的样本数量不多,那么Macro和Micro没有太大差异
- 如果每个类别的样本数量差异很大,那么注重样本量多的类时用Micro,注重样本量少的类时用Macro
- 如果Macro>>Micro的值,那么检查样本量多的类来确定指标表现差的原因
- 如果Micro>>Macro的值,那么检查样本量少的类来确定指标表现差的原因
召回率
召回率指实际为正的样本中,预测也为正的样本 占 实际为正的样本的比例。计算公式为
$$ \text{recall}=\frac{\text{TP}}{\text{TP}+\text{FN}} $$
代码如下
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是精确率和召回率的加权平均值,计算公式为
$$ \text{F1-score}=\frac{2*\text{precision}*\text{recall}}{\text{precision}+\text{recall}} $$
Precision体现了模型对负样本的区分能力,Precision越高,模型对负样本的区分能力越强
Recall体现了模型对正样本的识别能力,Recall越高,模型对正样本的识别能力越强
F1-score是两者的综合,F1-score越高,说明模型越稳健
代码如下
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{aligned} \text{precision}&=\frac{16}{16+2}=\frac{8}{9}\\ \text{Recall}&=\frac{16}{16+4}=\frac{4}{5}\\ \text{F1-score}&=\frac{2*\frac{8}{9}*0.8}{\frac{8}{9}+0.8} = a \end{aligned} $$
对于垃圾邮件
$$ \begin{aligned} \text{precision}&=\frac{3}{3+4}=\frac{3}{7}\\ \text{Recall}&=\frac{3}{3+2}=\frac{3}{5}\\ \text{F1-score}&=\frac{2*\frac{3}{7}*0.6}{\frac{3}{7}+0.6} = b \end{aligned} $$
对于整体的所有邮件
$$ \begin{aligned} \text{P} &= \frac{\frac{8}{9}+\frac{3}{7}}{2} \\ \text{R} &= \frac{0.8+0.6}{2}\\ \text{F1} &= \frac{a+b}{2} \end{aligned} $$