ROC曲线
1. ROC曲线的定义
ROC的全称是Receiver Operating Characteristic Curve,中文名字叫“受试者工作特征曲线”,顾名思义,其主要的分析方法就是画这条特征曲线。这里在网上找了一个比较好的图样示例如下,
该曲线的横坐标为假阳性率(False Positive Rate, FPR),N是真实负样本的个数,FP是N个负样本中被分类器预测为正样本的个数。
纵坐标为真阳性率(True Positive Rate, TPR),
P是真实正样本的个数,TP是P个正样本中被分类器预测为正样本的个数。
举一个简单的例子方便大家的理解,还是刚才雷达的例子。假设现在有10个雷达信号警报,其中8个是真的轰炸机(P)来了,2个是大鸟(N)飞过,经过某分析员解析雷达的信号,判断出9个信号是轰炸机,剩下1个是大鸟,其中被判定为轰炸机的信号中,有1个其实是大鸟的信号(FP=1),而剩下8个确实是轰炸机信号(TP=8)。因此可以计算出FPR为,TPR为,而就对应ROC曲线上一点。
说到这里,想必大家已经明白这俩个指标的计算方法,再往深挖一点,可以思考一下这俩个指标背后的原理。还是雷达的例子,敏锐的雷达系统我们肯定希望它能把所有的敌方轰炸机来袭都感知到并预测出来,即TPR越高越好,但我们又不希望它把大鸟的飞过也当成轰炸机来预警,即FRP越低越好。因此,大家可以发现,这俩个坐标值其实是有相互制约的一个概念在里面。
当绘制完成曲线后,就会对模型有一个定性的分析,如果要对模型进行量化的分析,此时需要引入一个新的概念,就是AUC(Area under roc Curve)面积,这个概念其实很简单,就是指ROC曲线下的面积大小,而计算AUC值只需要沿着ROC横轴做积分就可以了。真实场景中ROC曲线一般都会在这条直线的上方,所以AUC的取值一般在0.5~1之间。AUC的值越大,说明该模型的性能越好。
2. ROC曲线的绘制原理
如果大家对二值分类模型熟悉的话,都会知道其输出一般都是预测样本为正例的概率,而事实上,ROC曲线正是通过不断移动分类器的“阈值”来生成曲线上的一组关键点的。可能这样讲有点抽象,还是举刚才雷达兵的例子。每一个雷达兵用的都是同一台雷达返回的结果,但是每一个雷达兵内心对其属于敌军轰炸机的判断是不一样的,可能1号兵解析后认为结果大于0.9,就是轰炸机,2号兵解析后认为结果大于0.85,就是轰炸机,依次类推,每一个雷达兵内心都有自己的一个判断标准(也即对应分类器的不同“阈值”),这样针对每一个雷达兵,都能计算出一个ROC曲线上的关键点(一组FPR,TPR值),把大家的点连起来,也就是最早的ROC曲线了。
为方便大家进一步理解,本菇也在网上找到了一个示例跟大家一起分享【4】。下图是一个二分模型真实的输出结果,一共有20个样本,输出的概率就是模型判定其为正例的概率,第二列是样本的真实标签。
现在我们指定一个阈值为0.9,那么只有第一个样本(0.9)会被归类为正例,而其他所有样本都会被归为负例,因此,对于0.9这个阈值,我们可以计算出FPR为0,TPR为0.1(因为总共10个正样本,预测正确的个数为1),那么我们就知道曲线上必有一个点为(0, 0.1)。依次选择不同的阈值(或称为“截断点”),画出全部的关键点以后,再连接关键点即可最终得到ROC曲线如下图所示。
其实还有一种更直观的绘制ROC曲线的方法,这边简单提一下。就是把横轴的刻度间隔设为,纵轴的刻度间隔设为,N,P分别为负样本与正样本数量。然后再根据模型的输出结果降序排列,依次遍历样本,从0开始绘制ROC曲线,每遇到一个正样本就沿纵轴方向绘制一个刻度间隔的曲线,每遇到一个负样本就沿横轴方向绘制一个刻度间隔的曲线,遍历完所有样本点以后,曲线也就绘制完成了。究其根本,其最大的好处便是不需要再去指定阈值寻求关键点了,每一个样本的输出概率都算是一个阈值了。当然,无论是工业界还是学术界的实现,都不可能手动去绘制,下面就来讲一下如何用Python高效绘制ROC曲线。
3. ROC曲线绘制的Python实现
熟悉sklearn的读者肯定都知道,几乎所有评估模型的指标都来自sklearn库下面的metrics,包括计算召回率,精确率等。ROC曲线的绘制也不例外,都得先计算出评估的指标,也就是从metrics里面去调用roc_curve, auc,然后再去绘制。
from sklearn.metrics import roc_curve, auc
roc_curve和auc的官方说明教程示例如下
# 数据准备 >>> import numpy as np >>> from sklearn import metrics >>> y = np.array([1, 1, 2, 2]) >>> scores = np.array([0.1, 0.4, 0.35, 0.8]) # roc_curve的输入为 # y: 样本标签 # scores: 模型对样本属于正例的概率输出 # pos_label: 标记为正例的标签,本例中标记为2的即为正例 >>> fpr, tpr, thresholds = metrics.roc_curve(y, scores, pos_label=2) # 假阳性率 >>> fpr array([ 0. , 0.5, 0.5, 1. ]) # 真阳性率 >>> tpr array([ 0.5, 0.5, 1. , 1. ]) # 阈值 >>> thresholds array([ 0.8 , 0.4 , 0.35, 0.1 ]) # auc的输入为很简单,就是fpr, tpr值 >>> auc = metrics.auc(fpr, tpr) >>> auc 0.75
因此调用完roc_curve以后,我们就齐全了绘制ROC曲线的数据。接下来的事情就很简单了,调用plt即可,还是用官方的代码示例一步到底。
import matplotlib.pyplot as plt plt.figure() lw = 2 plt.plot(fpr, tpr, color='darkorange', lw=lw, label='ROC curve (area = %0.2f)' % auc) plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--') plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate') plt.title('Receiver operating characteristic example') plt.legend(loc="lower right") plt.show()
最终生成的ROC曲线结果如下图。