机器学习评估指标

引言

在机器学习中,我们需要评估模型的好坏,初学时,会认为有准确率就可以了,即模型作出正确的判断次数除以总的测试次数,公式化为:\(corret\_times/total\_times\)。但这种方式并不合理,试想有100个被试,其中1人感染疾病,其余99人正常,如果模型设置为不管任何输入,输出都正常,则这个模型的准确率就能达到99%了,按上面公式来看,这个无用的模型貌似ok。

实际上,机器学习有很多约定俗成的评估指标,最常用的就是精确率(precision),召回率(recall),F1值,以及ROC,AUC。其中AUC指标往往作为推荐系统排序的指标。

本文主要介绍混淆矩阵,以及上述指标的基本概念。这部分概念非常基础,资料很多,但往往又比较容易搞混,所以我尝试在合理的地方举一些例子说明,避免混淆概念。

混淆矩阵

很多机器学习问题都可以归结为二分类问题,同样地,评估标准也可以从二分类入手,标准答案有对错两种可能,预测模型也会对样本预测对错两种可能,所以一共有4种可能。以开篇为例,得病为正类(Positive,简称P),不得病为负类(Negative,简称N),于是有4种可能的组合,如下图所示:

\答案
预测 \
PN
PTPFP
NFNTN

上图就是赫赫有名的混淆矩阵。首先看出坐标是预测结果,横坐标是标准答案;

然后,组合中的第二个字母,是预测状态,第一个字母,表示预测与标准答案是否符合,预测正确为T(True),预测错误为F(False)。比如:

第一行

  • TP:预测是Positive,所以第二个字符是P,标准答案也是Positive,所以第一个字符是T(True);
  • FP:预测是Positive,所以第二个字符是P,标准答案则是Negative,所以第一个字符F(False),也就是这个预测是错的;

第二行:

  • FN:预测是Negative,所示第二个字符是N,标准答案却是Positive,所以第一个字符是F(False),也就是预测错了;
  • TN:预测是Negative,所以第二个字符是N,标准答案也是Negative,所以预测对了,第一个字符是T(True)。

很多教科书会管TP叫真阳,FP为假阳,TN为真阴,FN为假阴,道理是相通的,只是感觉翻译出来有点拗口,有我说的这种方式可能更好理解一些,理解后,这些真假阴阳也就再也不会混了。混淆矩阵有以下性质:

  • 样本全集=\(TP\cup FP\cup FN\cup TN\)
  • 任何一个样本属于且只属于4个集合中的一个,也就是它们之间没有交集。

理解了混淆矩阵,后面的所有概念就都很好理解了😄。

精确率

精确率(Precision,简称P值),指的是预测结果中正类数量占全部结果的比率,即\(P=\frac{TP}{TP+FP}\),在开篇说的病人例子里面,P为感染的病人,TP没有检测出来,则P=0,劣质的模型一下便无所遁形。

这里有的人会认为,如果把正负标准变一下,让P为正常人群,N为感染人群,这样P就是99%了,劣质模型不是依然横行吗?但在工程实践中,我们优先会把关注的指标作为正类。比如推荐系统,物料可能有几百万,但用户点击(真正关注)的物料可能只有几百个,这些物料正是模型需要学习训练的,而不关注的那百万种物料,对模型用处相对就没那么大了。

召回率

引用《自然语言处理入门》所说,召回率(recall)在英文中是“回想起”的意思,能回想起来的比例就是召回率(初学时,会很容易被这些莫名其妙的翻译搞得一头雾水,所以体会英文意思,会对理解概念有所帮助)。用公式表示:

$$R=\frac{TP}{TP+FN}$$

还是以开篇的病人感染为例,R值依然为0。从侧面证实了指标的合理性。

如何看到这里,还有不太明白的地方,可以记住一个例子,一条河里,有1400条鲤鱼,300只虾,300只鳖。现在以捕鲤鱼为目的。撒一大网,逮着了700条鲤鱼,200只虾,100只鳖(识别为Positive)。那么,这些指标分别如下:

  • 精确率=700/(700+200+100) = 70%
  • 召回率=700/1400=50%,这里的FN,可以理解为漏网之鱼,即模型(网)识别为不是鲤鱼(没捞着)的数量。

F1值

实践中,我们会发现,Precision和Recall是挺矛盾的一对指标,recall变大的时候,往往precision会降低,precision提升后,recall又会变低。为了综合两个指标,因此人们发明了F1值,定义如下:

$$\frac{1}{F1}=\frac{1}{P}+\frac{1}{R}$$

转化后,成为:F1=2*P*R/(P+R)

这样,P和R必须同时高,则F1才会得到高分。事实上,很多模型竞赛,也是看F1

值的。

AUC

概念

AUC,英文为Are Under Curve,也是一个评测分类模型好坏的指标。在混淆矩阵基础上,引入两个指标:

$$TPR=\frac{TP}{TP+FN}$$
$$FPR=\frac{FP}{FP+TN}$$

仔细看一下,TPR含义是答案为Positive、模型猜对的比例(模型也预测为Positive);
而FPR答案为Negative、模型猜错的比例(模型猜成Positive了)。
另外,可以看出TPR其实就是召回率,只是换个说法而已,因为这里的指标不同了。

从公式上看,感性的认识肯定是TPR值越高越好,而FPR的值应该越低越好。AUC的图像大致如下:

ROC图像

上图是一个典型的ROC图像,横坐标为TPR,纵坐标为FPR,实线下方的面积就是AUC值。上图可以看到,绝大部分点,TPR是大于FPR的,所以这个模型还是可以的。很多初学同学肯定疑惑,这些TPR,FPR坐标点是怎么得出来的,下面将重点说明一下。

AUC中的TPR、FPR与特性

在推荐系统中,训练好的模型会对测试集进行预测,得到预测的点击概率,如下图所示:

用户行为序列是否点击(答案)预测值
a1,a2,…,an10.35
b1,b2,…,bm10.22
c1,c2,…,cp00.01

AUC就是基于上表数据进行计算的。具体是进行按照分数进行倒序排列,以第一个值为准,凡大于该值为1,小于该值为0,计算一次TPR和FPR,得到一个坐标点;然后以第二个值为准,凡大于该值为1,小于该值为0,计算一次TPR和FPR,得到一个坐标点,如此类推,从而绘制出ROC图形。

具体的话,请看下面一个例子,如经过score排序后,得到的排序表格如下(用户行为序列对auc计算没有帮助,不列入表格中):

表1 demo

是否点击(答案)预测值
10.35
10.32
10.25
00.2
10.15
10.1

说明:上表只是一个例子,数据都是造的。下面通过代码计算ROC曲线(show me the code)。

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

##### 具体可参考 https://www.zhihu.com/question/39840928?from=profile_question_card 中"刘站奇"的回答,本代码在参考后,有所修改
#### 生成数据 #####
dict = {
    'label': [1, 1, 1, 0, 1, 0],
    'score': [0.35, 0.32, 0.25, 0.2, 0.15, 0.1]
}
df = pd.DataFrame(dict)

### 1. 先对value进行排序 ####
df.sort_values('score', inplace=True, ascending=False)
### 2. 对每条记录,计算其TPR和FPR ######
TPRandFPR = pd.DataFrame(index=range(len(df)), columns=('TP', 'FP'))
for i in range(len(df)):
    data = df.head(n=i + 1)
    score_threshold = data.tail(1)['score'].squeeze()
    FP = len(data[data['label'] == 0][data['score'] >= score_threshold])
    FPR = FP / float(len(df[df['label'] == 0]))
    TP = len(data[data['label'] == 1][data['score'] >= score_threshold])
    TPR = TP / float(len(df[df['label'] == 1]))
    print(str(FPR), ',' + str(TPR))
    TPRandFPR.iloc[i] = [TPR, FPR]

#### 3. 根据TPR,FPR画ROC曲线 ####
from sklearn.metrics import auc

AUC = auc(TPRandFPR['FP'], TPRandFPR['TP'])
plt.scatter(x=TPRandFPR['FP'], y=TPRandFPR['TP'], label='(FPR,TPR)', color='k')
plt.plot(TPRandFPR['FP'], TPRandFPR['TP'], 'k', label='AUC = %0.2f' % AUC)
plt.legend(loc='lower right')
plt.title('Receiver Operating Characteristic')
plt.plot([(0, 0), (1, 1)], 'r--')
plt.xlim([-0.01, 1.01])
plt.ylim([-0.01, 01.01])
plt.ylabel('True Positive Rate')
plt.xlabel('False Positive Rate')
plt.show()

这段代码可以直接复制使用,画出的图像如下:

表1的 ROC曲线

如果还不太明白ROC曲线,可以跟着上面代码,单步调试一下,就能掌握了(区区40行代码,还是很容易的)。这里数据生成,也可以读文件,稍微改造一下,就可以计算成ROC了。

这里有同学会问为什么要对score倒序?这个问题其实挺好的。其实这是因为在推荐系统中,往往并不太关注推送列表中的每一个item是否是准确的(其实用户自己都不一定确认每个item是不是对的),算法在召回时,只能尽可能地把用户感兴趣的items给召回回来,然后在精排时,将一系列特征喂到模型里面计算,得到的分值进行排序,预估点击概率高的排前面,点击概率低的排后面。

回到问题,按照score逆序后,就是模拟推荐列表,计算TPR、FPR的关系,TPR比FPR高,说明预估正确占比比错误占比高,从而认为排序是比较合理的。

细心的同学可能会发现一个问题,AUC高,并不代表上文说的F1就高,事实上,AUC更偏向于预估排序的合理性(当然,只是一定程度上而已),所以经常用于推荐系统,而F1值更多用于评估分类问题。

X. 附录

AUC 知乎:https://www.zhihu.com/question/39840928?from=profile_question_card,讲的非常好,认真看完,AUC肯定能明白
AUC计算:https://blog.csdn.net/qq_22238533/article/details/78666436

发表评论

电子邮件地址不会被公开。