阅读 107

ROC AUC 代价曲线

  • 1.ROC(Receiver Operation Characteristic)

我们根据学习器的预测结果对样例进行排序,按此顺序逐个把样本作为正例进行预测,每次计算出两个重要量的值,与P—R曲线的使用查准率与查全率为纵,横轴不同,ROC曲线的纵轴是“真正例率(TPR,True Positive Rate)”横轴是“假正例率(False Positive Rate)”.


  • 2.AUC(Area Under ROC Curve)与rank—loss

进行学习器比较时,与P—R图相似,若一个学习器的ROC曲线被另一个学习器的曲线完全“包住”,则可以断言后者的性能优于前者;若两个学习器的ROC曲线发生交叉,则难以一般性地断言两者孰优孰劣,此时如果一定要进行比较,则较为合理的判断依据是比较ROC曲线下的面积,即AUC.

形象化地看,AUC考虑的是样本预测的排序质量,因此它与排序误差有紧密联系

若正例的预测值小于反例,则记1个罚分,若相等则记0.5个罚分(可以理解成线代里面的逆序对数量),那么rank—loss对应的是ROC曲线之上的面积


  • 3.cost curve(代价曲线)

明确参数 : p=m+/m

目的:对于一个模型,根据p不同,找到使得代价总期望最小的模型的阈值

横轴:归一化的正概率代价期望

纵轴:归一化的总代价期望

大致过程:给定p,给定模型根据归一化代价期望的最小值
确定混淆矩阵的成分比例,阈值决定了这个比例,那如果这个比例确定了,阈值也就确定了,所以这时模型的阈值也对应确定下来了,也就是模型固定下来了
同时模型的综合考量指标P,R,F1,Fbeta等都确定下来了


  • 4 .实例

  • 4.1一个阈值对应一条直线

  • 4.1.1 引入模型:

下面我们用实例来说明一个阈值对应一条直线,我们的例子是一个二分类问题,它是五还是不是五,样本是如图所示的十二张图片进入该分类器后,给其打分

评判标准:得分越高的越是五,得分越低的越不是五

  • 4.1.2 代码试验:
import pandas as pd
import matplotlib as pml
import  matplotlib.pyplot as plt


#函数输出打分,从左到右分数依次增高
#1 2 3 4 5 6 7 8 9 10 11
output_score=list(range(12))

#正确分类,是五还是不是五
y=[0,0,0,0,1,0,1,1,0,1,1,1]

#p为样例是正例的概率(实际情况的正例率),取值范围[0,1],集合中正例的比例(m+/m),此时刚好为顺序排列
p=list(range(0,100,10))
p=[i/100 for i in p]
#[0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]

#设定代价
c01=3
c02=2

#一个阈值
theta=6.5

#根据阈值和打分情况判断是5还是不是5,0代表是5,1代表是5
def calculate_output_result(output_score,theta):
    output_result=[]
    for i in range(len(output_score)):
        if output_score[i]<theta:
            output_result.append(0)#小于theta记为0
        else:
            output_result.append(1)#大于theta记为1
    return output_result
#output_result为我们自己的判断
output_result=calculate_output_result(output_score,theta)

#统计y中的正例(m+),反例(m-)个数
def calculate_m_positive_negtive(y):
#value_counts确认数据出现的频率。
    result = pd.value_counts(y)
    m_positive=result[0]
    m_negative=result[1]
    return m_positive,m_negative
m_positive,m_negative=calculate_m_positive_negtive(y)

#m_positive=6,m_negative=6
#output_result为[0,0,0,0,0,0,0,1,1,1,1,1]为预测分类
#y为[0,0,0,0,1,0,1,1,0,1,1,1]为正确分类
#然后根据我们预测的值去计算混淆矩阵
def calculate_confusion(y,output_result):
    TP=0
    FN=0
    FP=0
    TN=0
    for i in range(len(y)):
        if y[i]==1:
            if y[i]==output_result[i]:
                TP+=1
            else:
                FN+=1
        else:
            if y[i]==output_result[i]:
                TN+=1
            else:
                FP+=1
    return TP,FN,FP,TN
TP,FN,FP,TN=calculate_confusion(y,output_result)

#计算得TP,FN,FP,TN分别为4 2 1 5

#求几个比例,保留四位小数
def calculate_FNR_FPR(TP,FN,FP,TN):
    FNR=round(FN/(FN+TP),4)
    FPR=round(FP/(FP+TN),4)
    return FNR,FPR
FNR,FPR=calculate_FNR_FPR(TP,FN,FP,TN)

#FNR为0.333 FTR为0.1667

#计算 正概率代价(横轴)
def calculate_Pcost(p,c01,c02):
    Pcosts=[]
    for i in range(len(p)):
        Pcost=round(p[i]*c01/(p[i]*c01+(1-p[i])*c02),4)
        Pcosts.append(Pcost)
    return Pcosts
Pcosts=calculate_Pcost(p,c01,c02)

#Pcosts为:[0.0, 0.1429, 0.2727, 0.3913, 0.5, 0.6, 0.6923, 0.7778, 0.8571, 0.931]

#计算 归一化总概率(纵轴)
def calculate_cost_norm(p,c01,c02,FNR,FPR):
    costs_norm=[]
    for i in range(len(p)):
        cost_norm=round((FNR*p[i]*c01+FPR*(1-p[i])*c02)/(p[i]*c01+(1-p[i])*c02),4)
        costs_norm.append(cost_norm)
    return  costs_norm
costs_norm=calculate_cost_norm(p,c01,c02,FNR,FPR)

#costs_norm为:[0.1667, 0.1905, 0.2121, 0.2319, 0.25, 0.2667, 0.282, 0.2963, 0.3095, 0.3218]

#画出图像,对比两种不同的横轴下的图像
def plot_lines(X,Y,color):
    plt.plot(X,Y,color)
    return
plot_lines(Pcosts,costs_norm,'r')
plot_lines(p,costs_norm,"b:")
plt.show()
  • 4.1.3 实验结果:
  • 4.1.4 反思:

1.如果我们使用Pcosts作为横轴,得出的是红色直线,而以p作为横轴,得出的是紫色弯曲虚线,不是一个线性关系,虽然我们想要的就是已知某一个p,我们到底应该对应哪一条曲线的θ值更好,但是不能拿p当横轴,因为其返回曲线是非线性的,不利于我们分析。

2.当p等于0时Pcosts等于0,cost_norm=FPR;当p等于1时Pcosts等于1,cost_norm=FNR

3.p的含义:连接两点的线段如何用参数方程表示?假设两点分别是A,B,如果想表示AB连线所有点的集合用λA+(1-λ)B,λ∈[0,1],通过λ的变化,我们可以得到线段AB。、

  • 4.2 多条直线围成代价敏感曲线

生成多个阈值下的曲线

  • 4.2.1代码实验
import pandas as pd
import matplotlib as pml
import  matplotlib.pyplot as plt


#函数输出打分,从左到右分数依次增高
#1 2 3 4 5 6 7 8 9 10 11
output_score=list(range(12))

#正确分类,是五还是不是五
y=[0,0,0,0,1,0,1,1,0,1,1,1]

#p为样例是正例的概率(实际情况的正例率),取值范围[0,1],集合中正例的比例(m+/m),此时刚好为顺序排列
p=list(range(0,100,10))
p=[i/100 for i in p]
#[0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]

#设定代价
c01=3
c02=2

#根据阈值和打分情况判断是5还是不是5,0代表是5,1代表是5
def calculate_output_result(output_score,theta):
    output_result=[]
    for i in range(len(output_score)):
        if output_score[i]<theta:
            output_result.append(0)#小于theta记为0
        else:
            output_result.append(1)#大于theta记为1
    return output_result

#统计y中的正例(m+),反例(m-)个数
def calculate_m_positive_negtive(y):
#value_counts确认数据出现的频率。
    result = pd.value_counts(y)
    m_positive=result[0]
    m_negative=result[1]
    return m_positive,m_negative

def calculate_confusion(y,output_result):
    TP=0
    FN=0
    FP=0
    TN=0
    for i in range(len(y)):
        if y[i]==1:
            if y[i]==output_result[i]:
                TP+=1
            else:
                FN+=1
        else:
            if y[i]==output_result[i]:
                TN+=1
            else:
                FP+=1
    return TP,FN,FP,TN

#求几个比例,保留四位小数
def calculate_FNR_FPR(TP,FN,FP,TN):
    FNR=round(FN/(FN+TP),4)
    FPR=round(FP/(FP+TN),4)
    return FNR,FPR

#计算 正概率代价(横轴)
def calculate_Pcost(p,c01,c02):
    Pcosts=[]
    for i in range(len(p)):
        Pcost=round(p[i]*c01/(p[i]*c01+(1-p[i])*c02),4)
        Pcosts.append(Pcost)
    return Pcosts

#计算 归一化总概率(纵轴)
def calculate_cost_norm(p,c01,c02,FNR,FPR):
    costs_norm=[]
    for i in range(len(p)):
        cost_norm=round((FNR*p[i]*c01+FPR*(1-p[i])*c02)/(p[i]*c01+(1-p[i])*c02),4)
        costs_norm.append(cost_norm)
    return  costs_norm


######################################################
#生成多个θ的时候
thetas=list(range(12))
thetas=[i+0.5 for i in thetas]
#生成12个θ:[0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5, 11.5]

#计算每个θ对应的点的函数,并存在列表里
def calculate_Pcost_cost_norm(thetas,output_score,y,calculate_Pcost,calculate_cost_norm):
    Pcosts_n=[]
    costs_norm_n=[]
    theta_FPR_FNR={}
    for i in range(len(thetas)):
        theta=thetas[i]

        #计算输出结果
        output_result=calculate_output_result(output_score,theta)

        #统计正反例个数
        m_positive,m_negative=calculate_m_positive_negtive(y)

        #计算混淆矩阵
        TP,FN,FP,TN=calculate_confusion(y,output_result)

        #计算FNR,FPR
        FNR,FPR=calculate_FNR_FPR(TP,FN,FP,TN)
        theta_FPR_FNR[theta]=[FNR,FPR]

        #正概率代价
        Pcosts=calculate_Pcost(p,c01,c02)
        Pcosts_n.append(Pcosts)

        #归一化总概率
        costs_norm=calculate_cost_norm(p,c01,c02,FNR,FPR)
        costs_norm_n.append(costs_norm)

    return Pcosts_n,costs_norm_n,theta_FPR_FNR

#调用函数计算每个θ对应的点
Pcosts_n,costs_norm_n,theta_FNR_FPR=calculate_Pcost_cost_norm(thetas,output_score,y,calculate_Pcost,calculate_cost_norm)

#画图
def plot_lines(X,Y,color):
    plt.plot(X,Y,color)
    return


for i in range(len(Pcosts_n)):
    plot_lines(Pcosts_n[i],costs_norm_n[i],'r')
plt.show()
  • 4.2.2 实验结果

作者:Tsukinousag

原文链接:https://www.jianshu.com/p/f1765b55c4b8

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐