一些定义
- 阳性(Positive, P),指样本中阳性的个数, P = T P + F N P=TP+FN P=TP+FN
- 阴性( Negtive,N),指样本中阴性的个数, N = T N + F P N=TN+FP N=TN+FP
- 假阳性(False Positive, FP),指预测中将阴性预测为阳性的个数
- 假阴性(False Negtive, FN),指预测中将阳性预测为阴性的个数
- 假阳性率(False Positive Rate, FPR),又叫误诊率,相当于假设检验中的取伪概率, F P R = F P / N FPR=FP/N FPR=FP/N.
- 真阳性率(True Positive Rate, TPR)又叫敏感性(sensitivity),召回率, T P R = T P / P . TPR=TP/P. TPR=TP/P.
- 查准率 P*(有些地方定义也是用P,为了避免和阳性P重复,这里加了个*号), P ∗ = T P / ( T P + F P ) P*=TP/(TP+FP) P∗=TP/(TP+FP) 。判断正确的阳性占全部判断为阳性的比例。
- 查全率R,和真阳性率TPR一个意思,又称为精确性(specificity) R = T P / ( T P + F N ) = T P / P R=TP/(TP+FN)=TP/P R=TP/(TP+FN)=TP/P.判断正确的阳性占全部真实阳性的比例。
通常我们用一个混淆矩阵直观表示上述概念:
ROC曲线
定义与解释
ROC曲线起源于第二次世界大战时期雷达兵对雷达的信号判断。ROC的全称是Receiver Operating Characteristic Curve,中文名字叫“受试者工作特征曲线”,顾名思义,其主要的分析方法就是画这条特征曲线.
上图的横轴代表假阳率(FPR),纵轴代表灵敏度(真阳率,TPR)。理想状态我们希望,FPR=0,TPR=1,也就是希望曲线能够尽可能接近(0,1)这一点。如果曲线在对角线之上,表明真阳率>假阳率,这是分类器才是有效的。反之,如果曲线在对角线或对角线之下,表明真阳率《假阳率,这时分类器是无效的。而曲线上的每一点对应一次调参的结果,所以最接近(0,1)点的值所对应的参数就是分类器的最优参数。
下面两幅图中两条ROC曲线相交于一点,AUC值几乎一样:当需要高Sensitivity时,模型A比B好;当需要高Speciticity时,模型B比A好;
ROC曲线的实现方法
画法一
ROC曲线上的每一个点都对应一次参数的调整,我们可以通过改变参数来逐步描绘出ROC曲线。可以举个例子来说明,譬如下表中的flag是样本的类别(1:Positive; 0:negtive),score是分类器(例如:logist regression)预测的该样本为阳性的概率, 我们需要调整的参数是threshold(如果score>threshold则判定为阳性,否则判定为阴性)。
这里我们可以设置参数的调整范围为0,0.1,0.2,…,0.9,1。于是可以做出ROC曲线为:
R语言实现
#用R语言实现
x=c(1,1,0,1,1,1,0,0,1,0,1,0,1,0,0,0,1,0,1,0)
score=c(0.9,0.8,0.7,0.6,0.55,0.54,0.53,0.52,0.51,0.505,0.4,0.39,0.38,0.37,0.36,0.35,0.34,0.33,0.30,0.1)
df=data.frame(flag=x,score=score)
index_P=df$flag==1
res=data.frame(TPR=NA,FPR=NA,threshold=NA)
res=res[-1,]
for(threshold in seq(0,1,0.001)){
pre_P=df$score>threshold
TPR=sum(pre_P[index_P]==1)/length(index_P)
FPR=sum(pre_P[!index_P]==1)/(nrow(df)-sum(index_P))
res=rbind(res,data.frame(TPR,FPR,threshold))
}
plot(res$FPR,res$TPR,type='b',xlab = "FPR",ylab='TPR',main = "ROC曲线")
效果 如下:
python语言实现
#python实现
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
x=[1,1,0,1,1,1,0,0,1,0,1,0,1,0,0,0,1,0,1,0]
score=[0.9,0.8,0.7,0.6,0.55,0.54,0.53,0.52,0.51,0.505,0.4,0.39,0.38,0.37,0.36,0.35,0.34,0.33,0.30,0.1]
df=pd.DataFrame({'flag':x,'score':score})
index_P=df['flag']==1
res=pd.DataFrame(columns=['TPR','FPR','threshold'])
for threshold in np.arange(0,1,0.001):
pre_P=df['score']>threshold
TPR=sum(pre_P[index_P]==1)/len(index_P)
FPR=sum(pre_P[~index_P]==1)/(df.shape[0]-sum(index_P))
res=res.append({'TPR':TPR,'FPR':FPR,"threshold":threshold},ignore_index=True)
res.plot(x='FPR',y='TPR',title="ROC curve",marker='o')
plt.show()
效果如下:
画法二
相比与画法一,这里的画法更加简单,不用每次重复计算TPR和FPR。
给定 P 个正例和N 个反例,根据学习器预测结果对样例进行排序,然后把分类阈值值设为最大,即把所有样例均预测为反例,此时真正例率TPR和假正例率FPR均为 0 , 在坐标 (0, 0) 处标记一个点然后,将分类阈值依次设为每个样例的预测值,即依次将每个样例划分为正例。设前一个标记点坐标为
(
x
,
y
)
(x, y)
(x,y) , 当前若为真正例,则对应标记点的坐标为
(
x
,
y
+
1
P
)
(x,y+\frac{1}{P})
(x,y+P1);当前若为假正例,则对应标记点的坐标为
(
x
+
1
N
,
y
)
(x +\frac{1}{N},y)
(x+N1,y) ,然后用线段连接相邻点即得.
AUC
AUC(Area under roc Curve)面积就是ROC曲线下面的面积,真实场景中ROC曲线一般都会在这条直线的上方,所以AUC的取值一般在0.5~1之间。AUC的值越大,说明该模型的性能越好。 常用来比较两个分类器的性能。
A U C = 1 2 ∑ i = 1 m − 1 ( x i + 1 − x i ) ( y i + y i + 1 ) . AUC=\frac{1}{2}\sum_{i=1}^{m-1}(x_{i+1}-x_i)(y_i+y_{i+1}). AUC=21i=1∑m−1(xi+1−xi)(yi+yi+1).
P-R曲线
与ROC曲线相比较,P-R曲线刻画的是查全率(TPR)与查准率的关系(P*)的关系,如下图所示:
由于我们希望TP的比例在真阳中假阳样本中的比例都尽可能大,也就是既希望查准率(P*)很大,也希望查全率(R,TPR)很大,那么该曲线越接近(1,1)越好。
上图中A曲线和B曲线有交叉地方,表明这两个分类器各有优劣,要具体情况比较。如果非要分个高下,可以利用**平衡点(Break-Event Point, BEP)**来比较,也即在查准率=查全率的时候,比较他们P-R曲线上点的大小。同样地,我们也可以利用曲线下的面积大小来进行比较。
但BEP还是过于简单了些,更常用的是F1度量:
F
1
=
2
×
P
∗
×
R
P
∗
+
R
=
2
×
T
P
P
+
N
+
T
P
−
T
N
F1=\frac{2\times P^*\times R}{P^*+R}=\frac{2\times TP}{P+N+TP-TN}
F1=P∗+R2×P∗×R=P+N+TP−TN2×TP
等价于:
1
F
1
=
1
2
(
1
P
+
1
R
)
.
\frac{1}{F1}=\frac{1}{2}\left(\frac{1}{P}+\frac{1}{R}\right).
F11=21(P1+R1).
进一步,由于对查准率和查全率的重视程度不同,我们还可以利用
F
β
F_\beta
Fβ度量:
F
β
=
(
1
+
β
2
)
×
P
∗
×
R
(
β
2
×
P
∗
)
+
R
,
F_\beta=\frac{(1+\beta^2)\times P^*\times R}{(\beta^2\times P^*)+R},
Fβ=(β2×P∗)+R(1+β2)×P∗×R,
等价于
1
F
β
=
1
β
2
(
1
P
+
β
2
R
)
.
\frac{1}{F_\beta}=\frac{1}{\beta^2}\left(\frac{1}{P}+\frac{\beta^2}{R}\right).
Fβ1=β21(P1+Rβ2).
以上两个度量都是基于调和平均的,之所以这样做是因为与算数平均和几何平均相比,调和平均更重视较小值.
代价敏感错误率与代价曲线
在实际中阳性识别为阴性和阴性识别为阳性的错误代价不同,由此可以构造一个代价矩阵:
一般情况下,重要的是代价比值而非绝对值,例如
c
o
s
t
01
:
c
o
s
t
10
=
5
:
2
cost_{01}:cost_{10}=5:2
cost01:cost10=5:2与50:10所起的效果相当。
令
D
+
D^+
D+与
D
−
D^-
D−分别代表样例集
D
D
D的正例和反例集,
m
m
m为总样本量,则**代价敏感(cost-sensitive)**错误率为
E
(
f
;
D
;
c
o
s
t
)
=
1
m
(
∑
x
i
∈
D
+
1
(
f
(
x
i
)
≠
y
i
)
×
c
o
s
t
01
+
∑
x
i
∈
D
−
1
(
f
(
x
i
)
≠
y
i
)
×
c
o
s
t
10
)
.
E(f;D;cost)=\frac{1}{m}\left(\sum_{x_i\in D^+}1(f(x_i)\neq y_i)\times cost_{01}+\sum_{x_i\in D^-}1(f(x_i)\neq y_i)\times cost_{10}\right).
E(f;D;cost)=m1(xi∈D+∑1(f(xi)=yi)×cost01+xi∈D−∑1(f(xi)=yi)×cost10).
在非均匀等代价下,ROC曲线不能直接反映出学习器的期望总体代价,而代价曲线(cost curve)则可达到该目的。代价曲线图的横轴是取值为
[
0
,
1
]
[0,1]
[0,1]的正例概率代价
P
(
+
)
c
o
s
t
=
p
×
c
o
s
t
01
p
×
c
o
s
t
01
+
(
1
−
p
)
×
c
o
s
t
10
,
P(+)cost=\frac{p\times cost_{01}}{p\times cost_{01}+(1-p)\times cost_{10}},
P(+)cost=p×cost01+(1−p)×cost10p×cost01,
其中
p
p
p是样例为正例的概率;纵轴是取值为[0,1]的归一化代价
c
o
s
t
n
o
r
m
=
F
N
R
×
p
×
c
o
s
t
01
+
F
P
R
×
(
1
−
p
)
×
c
o
s
t
10
p
×
c
o
s
t
01
+
(
1
−
p
)
×
c
o
s
t
10
cost_{norm}=\frac{FNR\times p\times cost_{01}+FPR\times (1-p)\times cost_{10}}{p\times cost_{01}+(1-p)\times cost_{10}}
costnorm=p×cost01+(1−p)×cost10FNR×p×cost01+FPR×(1−p)×cost10
其中
F
N
R
=
1
−
T
P
R
FNR=1-TPR
FNR=1−TPR是假反例率.
代价曲线的绘制方法:
ROC 由线上每一点对应了代价平面上的一条线段 , 设 ROC 曲线上点的坐标为 (TPR, FPR) ,则可相应计算出 FNR,然后在代价平面上绘制
一条从 (0 , FPR) 到 (1 , FNR) 的线段,线段下的面积即表示了该条件下的期望总体代价;如此将 ROC 曲线土的每个点转化为代价平面上的一条线段,然后取所有线段的下界,围成的自积即为在所有条件下学习器的期望总体代价,如图:
相关程序包
R语言中可以利用pROC包来绘制ROC曲线,使用roc函数的格式大致如下,
ci=T代表计算95%的置信区间,auc=T则会返回auc值,例如利用数据集aSAH来进行测试:
#R语言
library(pROC)
data(aSAH)
tmp=roc(aSAH$outcome, aSAH$s100b, smooth=TRUE,ci=T,auc = T)
plot(tmp)
#或者ggroc(tmp)
#python语言
from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as plt
x=[1,1,0,1,1,1,0,0,1,0,1,0,1,0,0,0,1,0,1,0]
score=[0.9,0.8,0.7,0.6,0.55,0.54,0.53,0.52,0.51,0.505,0.4,0.39,0.38,0.37,0.36,0.35,0.34,0.33,0.30,0.1]
fpr, tpr, thresholds = roc_curve(x, score)
#计算AUC值
roc_auc = auc(fpr, tpr)
#绘制ROC图
plt.plot(fpr,tpr)
plt.show()
可以参考:
https://www.freesion.com/article/2560277921/
参考
https://www.jianshu.com/p/2ca96fce7e81
https://www.plob.org/article/12476.html
《机器学习》周志华