-
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 实验结果
网友评论