详解支持向量机-基于SVM的ROC曲线和AUC面积菜菜的sklearn课堂笔记

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解支持向量机-基于SVM的ROC曲线和AUC面积菜菜的sklearn课堂笔记相关的知识,希望对你有一定的参考价值。

手动绘制SVM的ROC曲线

我们理解了什么是阈值(threshold),了解了不同阈值会让混淆矩阵产生变化,也了解了如何从我们的分类算法中获取概率。ROC是一条以不同阈值下的假正率FPR为横坐标,不同阈值下的召回率Recall为纵坐标的曲线。简单地来说,只要我们有数据和模型,我们就可以在python中绘制出我们的ROC曲线。

先用之前的回归案例,提取FPR和Recall

cm = CM(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])
cm
---
array([[4, 0],
       [2, 5]], dtype=int64)

# FPR
cm[1,0]/cm[1,:].sum()
---
0.2857142857142857

# Recall
cm[0,0]/cm[0,:].sum()
---
1.0

换到SVM上

# 概率 clf.predict_proba(X)[:,1] 类别1下的概率,因为我们一开始生成数据的时候少数类为1
# 阈值 基于概率的最大最小值,阈值就是概率的最大最小值之前的多个值,每一个阈值都对应着一次循环,每一次循环,都有一个混淆矩阵,要有一组假正率和召回率
recall = []
FPR = []
probrange = np.linspace(clf.predict_proba(X)[:,1].min(),clf.predict_proba(X)[:,1].max(),endpoint=False)
# 设置endpoint=False,不取到最大值(我感觉没啥影响,因为0也不再分母上)

for i in probrange: # 概率从最小值到最大值,也就是阈值的取值
    y_predict = []
    for j in range(X.shape[0]): # 样本从第一个到最后一个
        if clf.predict_proba(X)[j,1] > i:
            y_predict.append(1)
        else:
            y_predict.append(0)
    cm = CM(y,y_predict,labels=[1,0])
    recall.append(cm[0,0]/cm[0,:].sum())
    FPR.append(cm[1,0]/cm[1,:].sum())

FPR
# 一开始假正率是最大值,因为一开始阈值很小,也就是说即使有极小的概率这个样本是少数类,我们也认为它是少数类,因此有很多可能只有1%概率的样本因为阈值的限定被认定为少数类,导致假正率极大
# 到最后阈值极大,判定条件非常严格,正好与上面相反,因此假正率也就接近甚至达到0%
---
[0.998,
 0.302,
 0.206,
 0.166,
 0.148,
 ……
 0.006,
 0.002,
 0.0,
 0.0,
 0.0] 

plt.plot(list(reversed(FPR)),list(reversed(recall)),c=red)
# 这里FPR和recall列表是否翻转都可以,结果一样
plt.plot(probrange+0.05,probrange+0.05,c=k,linestyle=--)
plt.show()
# 选择x值小,y值大的位置
# 也就是假正率小,召回率大
# 也就是认定的少数类大多确实是真实地少数类,多数少数类被召回

横坐标是FPR,代表着模型将多数类判断错误的能力,纵坐标Recall,代表着模型捕捉少数类的能力,所以ROC曲线代表着,随着Recall的不断增加,FPR如何增加。我们希望随着Recall的不断提升,FPR增加得越慢越好,这说明我们可以尽量高效地捕捉出少数类,而不会将很多地多数类判断错误。所以,我们希望看到的图像是,纵坐标急速上升,横坐标缓慢增长,也就是在整个图像左上方的一条弧线。这代表模型的效果很不错,拥有较好的捕获少数类的能力。 中间的虚线代表着,当recall增加1%,我们的FPR也增加1%,也就是说,我们每捕捉出一个少数类,就会有一个多数类被判错。 ROC曲线通常都是凸型的。对于一条凸型ROC曲线来说,曲线越靠近左上角越好,越往下越糟糕,曲线如果在虚线的下方,则证明模型完全无法使用。但是它也有可能是一条凹形的ROC曲线。对于一条凹型ROC曲线来说,应该越靠近右下角越好,凹形曲线代表模型的预测结果与真实情况完全相反,那也不算非常糟糕,只要我们手动将模型的结果逆转,就可以得到一条左上方的弧线了。最糟糕的就是,无论曲线是凹形还是凸型,曲线位于图像中间,和虚线非常靠近,那我们拿它无能为力

sklearn中的ROC曲线和AUC面积

上面我们是手动计算ROC曲线上的点然后连线得到的,这里我们使用sklearn中包装好的方法来实现。能明显的感觉到,使用起来更便利,速度比之前更快

roc_curve(
    [y_true, y_score, pos_label=None, sample_weight=None, drop_intermediate=True],
)
# y_true:真实标签
# y_score:置信度分数,可以是正类样本的概率值,或置信度分数,或者decision_function返回的距离
# pos_label:整数或者字符串,表示被认为是正类样本的类别
# drop_intermediate:布尔值,默认True,如果设置为True,表示会舍弃一些ROC曲线上不显示的阈值点,这对于计算一个比较轻量的ROC曲线来说非常有用
# 注意这个类返回:FPR,Recall,阈值。
from sklearn.metrics import roc_curve

FPR,recall,thresholds = roc_curve(y,clf.decision_function(X),pos_label=1)

FPR.shape
---
(45,)

recall.shape
---
(45,)

thresholds.shape # 此时的threshold不是一个概率值,而是距离的阈值,可正可负
---
(45,)

thresholds
---
array([  3.18236076,   2.18236076,   1.48676267,   1.35964325,
	     0.88438995,  -0.91257798,  -1.01417607,  -1.08601917,
        -10.31959605])

判断ROC的好坏可以通过AUC面积来判定

roc_auc_score(y_true, y_score, average=macro, sample_weight=None, max_fpr=None)
# y_true:真实标签
# y_score:置信度分数,可以是正类样本的概率值,或置信度分数,或者decision_function返回的距离
area = AUC(y,clf.decision_function(X))
area
---
0.9696400000000001

画图

plt.figure()
plt.plot(FPR,recall,color=red
        ,label=ROC curve (area = %.2f)%area)
plt.plot([0,1],[0,1],color=k,linestyle=--)
plt.xlim([-0.05,1.05])
plt.ylim([-0.05,1.05])
plt.xlabel(False Positive Rate)
plt.ylabel(Recall)
plt.legend(loc=lower right)
plt.show()

如此就得到了我们的ROC曲线和AUC面积,可以看到,SVM在这个简单数据集上的效果还是非常好的。并且大家可以通过观察我们使用decision_function画出的ROC曲线,对比一下我们之前强行使用概率画出来的曲线,两者非常相似,所以在无法获取模型概率的情况下,其实不必强行使用概率,如果有置信度,那也使可以完成我们的ROC曲线的

利用ROC曲线找出最佳阈值

ROC曲线反应的是recall增加的时候FPR如何变化。我们的希望是,模型在捕获少数类的能力变强的时候,尽量不误伤多数类,也就是说,随着recall的变大,FPR的大小越小越好(同一模型下这是不可能的)。所以我们希望找到的最佳的阈值,其实是Recall和FPR差距最大的点。这个点,又叫做约登指数

recall - FPR
---
array([0.   , 0.02 , 0.014, 0.054, 0.052, 0.152, 0.15 , 0.19 , 0.186,
	   ……
	   0.814, 0.854, 0.848, 0.868, 0.866, 0.886, 0.874, 0.914, 0.   ])

maxindex = (recall - FPR).tolist().index(max(recall - FPR))
maxindex
---
43

thresholds[maxindex] # 用decision_function生成的置信度来说
---
-1.0860191749391461

plt.figure()
plt.plot(FPR,recall,color=red
        ,label=ROC curve (area = %.2f)%area)
plt.plot([0,1],[0,1],color=k,linestyle=--)
plt.scatter(FPR[maxindex],recall[maxindex],s=50,color=k)
# 画出最佳阈值,也就是根据约登指数得到的点
plt.xlim([-0.05,1.05])
plt.ylim([-0.05,1.05])
plt.xlabel(False Positive Rate)
plt.ylabel(Recall)
plt.legend(loc=lower right)
plt.show()

这个点,其实是图像上离左上角最近的点,离中间的虚线最远的点,也是ROC曲线的转折点。如果没有时间进行计算,或者横坐标比较清晰的时候,我们就可以观察转折点来找到我们的最佳阈值。

以上是关于详解支持向量机-基于SVM的ROC曲线和AUC面积菜菜的sklearn课堂笔记的主要内容,如果未能解决你的问题,请参考以下文章

详解支持向量机-ROC曲线中的概率和阈值菜菜的sklearn课堂笔记

R语言使用yardstick包的roc_auc函数和pr_auc函数分别计算二分类(binary)模型在ROC曲线下方的面积和PR曲线下方的面积AUC值(area under the curve)

ROC曲线,AUC面积

ACU个人详解的理解及代码实现

sklearn学习:为什么roc_auc_score()和auc()有不同的结果?

笔记︱统计评估指标AUC 详解