首页 > 其他分享 >详解支持向量机-基于SVM的ROC曲线和AUC面积【菜菜的sklearn课堂笔记】

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

时间:2022-11-29 22:02:04浏览次数:67  
标签:曲线 SVM 阈值 recall 菜菜 ROC plt FPR

视频作者:菜菜TsaiTsai 链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili

手动绘制SVM的ROC曲线

对于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值大的位置
# 也就是假正率小,召回率大
# 也就是认定的少数类大多确实是真实地少数类,多数少数类被召回

![[附件/Pasted image 20221028112638.png|350]]

之前我们说,通常来说,降低阈值能够升高Recall,有通常二字。 看上面这个图,显然是不平滑的,如果之前linspace切片数量进一步减少,甚至会出现下图的情况 ![[附件/Pasted image 20221028112919.png|200]] 根据我们之前生成的数据集来解释一下,为什么线是直上直下的,为了方便解释,我们这里的阈值使用距离也就是decision_function来衡量置信度 ![[附件/Pasted image 20221028110709.png|350]] 假设现在有一条超平面在红紫交界处,方向从左上到右下,我们向左下移动一点,假设只有一个样本点从超平面右侧移动到左侧

  • 如果说这个点是紫色点,那么受影响的是FPR,分母不变,分子变大,但此时recall不变,呈现在ROC曲线上就是向右的一小段线段
  • 如果说这个点是红色点,那么受影响的是recall,分母不变,分子变大,但此时FPR不变,呈现在ROC曲线上就是向上的一小段线段

这也就导致了即使我们移动了阈值,recall不一定升高,可能不变

图一作者:hedgehog小子 链接:ROC曲线与AUC - hedgehog小子 - 博客园 (cnblogs.com)

横坐标是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面积来判定

AUC面积是可以看做ROC曲线在$(0,1)$上的积分,面积越大越接近1越好(根据之前的理论,越小越接近0也可以越好,只要将模型翻转即可)

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()

![[附件/Pasted image 20221028160054.png|350]]

如此就得到了我们的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()

![[附件/Pasted image 20221028161035.png|350]]

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

到这里为止,SVC的模型评估指标就介绍完毕了。但是,SVC的样本不均衡问题还可以有很多的探索。另外,我们还可以使用KS曲线,或者收益曲线(profit chart)来选择我们的阈值,都是和ROC曲线类似的用法。大家若有余力,可以自己深入研究一下。模型评估指标,还有很多深奥的地方。

标签:曲线,SVM,阈值,recall,菜菜,ROC,plt,FPR
From: https://blog.51cto.com/u_15767241/5897142

相关文章

  • Rockwell EDI 855 采购订单确认报文详解
    罗克韦尔自动化与国内12家授权分销商,124家认可的系统集成商,30多家亚太区的Encompass战略合作伙伴和全球战略联盟,共同为制造业企业提供广泛的世界一流的产品、解决方案与......
  • ReadProcessMemory函数的分析
    ReadProcessMemory函数用于读取其他进程的数据。我们知道自远古时代结束后,user模式下的进程都有自己的地址空间,进程与进程间互不干扰,这叫私有财产神圣不可侵犯。但windows里......
  • docker部署RockerMQ单机测试环境
    1.RocketMQ创建专属网络[root@mq011~]#dockernetworkcreaterocketmq154dc65dce84ce5d417e9e2787bdd77de881ac65575e5e74fed4aeaf99830984[root@mq011~]#docker......
  • Backtrader - multiprocessing.pool.MaybeEncodingError: Error sending result
    1.ErrorMessagemultiprocessing.pool.MaybeEncodingError:Errorsendingresult:'[<backtrader.cerebro.OptReturnobjectat0x000002DF30503CF8>]'.Reason:'Pickl......
  • BrokenPipeError错误和subprocess.run()超时参数在Windows上无效
    1、问题的发现 今天,一个在windows上运行良好的python脚本放到linux下报错,提示错误BrokenPipeError:[Errno32]Brokenpipe。经调查是subprocess.run方法的timeout参数......
  • 详解支持向量机-ROC曲线中的概率和阈值【菜菜的sklearn课堂笔记】
    视频作者:菜菜TsaiTsai链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili基于混淆矩阵,我们学习了总共六个指标:准确率Accuracy,精确度Precisi......
  • Prometheus 监测 RocketMQ 最佳实践
    本文作者:郭雨杰,阿里云智能技术专家。Prometheus集成的50多款云产品中,RocketMQ在可观测方面实现了非常完善的功能,是一个特别具有代表性的云产品。RocketMQ如何接入......
  • 拓端tecdat|R语言编程指导画ROC曲线总结
    R语言画ROC曲线总结   在本文中,我描述了如何在CRAN中搜索用于绘制ROC曲线的包,并重点介绍了六个有用的包。尽管我从一些我想谈论的软件包开始就有......
  • GetWindowThreadProcessId
    ​​编辑本段​​一、VC--------------------------------------------------------------------------------TheGetWindowThreadProcessIdfunctionretrieves......
  • 读 RocketMQ 源码,学习并发编程三大神器
    笔者是RocketMQ的忠实粉丝,在阅读源码的过程中,学习到了很多编程技巧。这篇文章,笔者结合RocketMQ源码,分享并发编程三大神器的相关知识点。1CountDownLatch实现网络......