一. 机器学习分类器指标
首先需要建立一个表,对于一个分类任务,我们预测情况大致如下面混淆矩阵所示:
预测为正样本 | 预测为负样本 | |
---|---|---|
标签为正样本 | TP(ture positive) | FN(false negative) |
标签为负样本 | FP(false positive) | TN(true negative) |
1. 准确率(accuracy)
准确率(accuracy)指的是正确预测的样本数占总预测样本数的比值,它不考虑预测的样本是正例还是负例,考虑的是全部样本。
2.查准率(precision)
precision指的是正确预测的正样本数占所有预测为正样本的数量的比值,也就是说所有预测为正样本的样本中有多少是真正的正样本。从这我们可以看出,precision只关注预测为正样本的部分。
3. 召回率(recall)
它指的是正确预测的正样本数占真实正样本总数的比值,也就是我能从这些样本中能够正确找出多少个正样本。
4. F-score
是用来平衡Precision,Recall在F-score计算中的权重,取值情况有以下三种:
- 如果取1,表示Precision与Recall一样重要。
- 如果取小于1,表示Precision比Recall重要。
- 如果取大于1,表示Recall比Precision重要。
一般情况下认为两者同样重要即:
F-score相当于precision和recall的调和平均,用意是要参考两个指标。从公式我们可以看出,recall和precision任何一个数值减小,F-score都会减小,反之,亦然。
5. 特异性(specificity)
specificity指标平时见得不多,用来评价负样本的分类情况,它是相对于灵敏度(sensitivity)(也是召回率)而言的,指的是正确预测的负样本数占真实负样本总数的比值,也就是我能从这些样本中能够正确找出多少个负样本。
6. 灵敏度(sensitivity)
同召回率用来评价正样本的分类情况,一般情况下特异性和灵敏度同时用来评价疾病诊断,特异性来表示误诊率,灵敏度用来表示漏诊率。特异性越高表示误诊率低(TN越大,FP越小),灵敏度高表示漏诊率低(TP越大,FN越小),而TP+FN=正样本总数,TN+FP=负样本总数。
7. P-R曲线
我们将纵轴设置为precison,横轴设置成recall,改变阈值就能获得一系列的pair并绘制出曲线。对于不同的模型在相同数据集上的预测效果,我们可以画出一系列的PR曲线。一般来说如果一个P-R曲线完全“包围”另一个曲线,我们可以认为该模型的分类效果要好于对比模型。
如下图所示:
二、样本不均衡下的分类指标
在大多数情况下不同类别的分类代价并不相等,即将样本分类为正例或反例的代价是不能相提并论的。例如在垃圾邮件过滤中,我们希望重要的邮件永远不要被误判为垃圾邮件,还有在癌症检测中,宁愿误判也不漏判。在这种情况下,仅仅使用分类错误率来度量是不充分的,这样的度量错误掩盖了样本如何被错分的事实。所以,在分类中,当某个类别的重要性高于其他类别时,可以使用Precison和Recall多个比分类错误率更好的新指标。
1. ROC(Receiver Operating Characteristic Curve)
在实际的数据集中经常会出现类别不平衡现象,即负样本比正样本多很多(或者相反),而且测试数据中的正负样本的分布也可能随着时间而变化。而在这种情况下,ROC曲线能够保持不变。同时,我们可以断言,ROC曲线越接近左上角,该分类器的性能越好,意味着分类器在假阳率(False Positive Rate)很低的同时获得了很高的真阳率(True Positive Rate)。一般情况下,这个曲线都应该处于(0, 0)和(1, 1)连线的上方,因为(0, 0)和(1, 1)连线形成的ROC曲线实际上代表的是一个随机分类器。如果很不幸,你得到一个位于此直线下方的分类器的话,一个直观的补救办法就是把所有的预测结果反向,即:分类器输出结果为正类,则最终分类的结果为负类,反之,则为正类。
以下是一个ROC曲线的实例:
其中,该曲线的横坐标为假阳性率(False Positive Rate, FPR),N是真实负样本的个数,FP是N个负样本中被分类器预测为正样本的个数,P是真实正样本的个数。其中,
。
举个例子,如果有20个样本的2分类,分类结果如下所示:
现在我们指定一个阈值为0.9,那么只有第一个样本(0.9)会被归类为正例,而其他所有样本都会被归为负例,因此,对于0.9这个阈值,我们可以计算出FPR为0,TPR为0.1(因为总共10个正样本,预测正确的个数为1),那么我们就知道曲线上必有一个点为(0, 0.1)。依次选择不同的阈值(或称为“截断点”),画出全部的关键点以后,再连接关键点即可最终得到ROC曲线如下图所示。
其实还有一种更直观的绘制ROC曲线的方法,就是把横轴的刻度间隔设为,纵轴的刻度间隔设为
,N,P分别为负样本与正样本数量。然后再根据模型的输出结果降序排列,依次遍历样本,从0开始绘制ROC曲线,每遇到一个正样本就沿纵轴方向绘制一个刻度间隔的曲线,每遇到一个负样本就沿横轴方向绘制一个刻度间隔的曲线,遍历完所有样本点以后,曲线也就绘制完成了。
使用sklearn进行roc曲线绘制
>>> from sklearnimport metrics
>>> import numpy as np
>>> y = np.array([1, 1, 2, 2]) #假设4个样本
>>> scores = np.array([0.1, 0.4, 0.35, 0.8])
>>> fpr, tpr, thresholds = metrics.roc_curve(y, scores, pos_label=2)
>>> fpr #假阳性
array([ 0. , 0.5, 0.5, 1. ])
>>> tpr #真阳性
array([ 0.5, 0.5, 1. , 1. ])
>>> thresholds #阈值
array([ 0.8 , 0.4 , 0.35, 0.1 ])
>>> #auc(后面会说)
>>> auc = auc = metrics.auc(fpr, tpr)
>>> auc
0.75
绘制曲线:
import matplotlib.pyplot as plt
plt.figure()
lw = 2
plt.plot(fpr, tpr, color='darkorange',
lw=lw, label='ROC curve (area = %0.2f)' % auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()
所画图象如图所示:
2. AUC(Area Under roc Curve)
虽然,用ROC curve来表示分类器的performance很直观好用。可是,人们总是希望能有一个数值来标志分类器的好坏。于是Area Under roc Curve(AUC)就出现了。顾名思义,AUC的值就是处于ROC curve下方的那部分面积的大小。通常,AUC的值介于0.5到1.0之间,较大的AUC代表了较好的performance。
AUC指的是计算ROC的面积。假设分类器的输出是样本属于正类的socre(置信度),则AUC的物理意义为,任取一对(正、负)样本,正样本的score大于负样本的score的概率。另一种理解,AUC值是一个概率值,当你随机挑选一个正样本以及负样本,当前的分类算法根据计算得到的Score值将这个正样本排在负样本前面的概率就是AUC值,AUC值越大,当前分类算法越有可能将正样本排在负样本前面,从而能够更好地分类。
总得来说:AUC值为ROC曲线所覆盖的区域面积,显然,AUC越大,分类器分类效果越好。
- AUC = 1,是完美分类器,采用这个预测模型时,不管设定什么阈值都能得出完美预测。绝大多数预测的场合,不存在完美分类器。
- 0.5 < AUC < 1,优于随机猜测。这个分类器(模型)妥善设定阈值的话,能有预测价值。
- AUC = 0.5,跟随机猜测一样(例:丢铜板),模型没有预测价值。
- AUC < 0.5,比随机猜测还差;但只要总是反预测而行,就优于随机猜测。
def AUC(label, pre):
"""
适用于python3.0以上版本
"""
#计算正样本和负样本的索引,以便索引出之后的概率值
pos = [i for i in range(len(label)) if label[i] == 1]
neg = [i for i in range(len(label)) if label[i] == 0]
auc = 0
for i in pos:
for j in neg:
if pre[i] > pre[j]:
auc += 1
elif pre[i] == pre[j]:
auc += 0.5
return auc / (len(pos)*len(neg))
if __name__ == '__main__':
label = [1,0,0,0,1,0,1,0]
pre = [0.9, 0.8, 0.3, 0.1, 0.4, 0.9, 0.66, 0.7]
print(AUC(label, pre))
当然,也可以使用公式来进行计算:
代码如下:
import numpy as np
def auc_calculate(labels,preds,n_bins=100):
postive_len = sum(labels)
negative_len = len(labels) - postive_len
total_case = postive_len * negative_len
pos_histogram = [0 for _ in range(n_bins)]
neg_histogram = [0 for _ in range(n_bins)]
bin_width = 1.0 / n_bins
for i in range(len(labels)):
nth_bin = int(preds[i]/bin_width)
if labels[i]==1:
pos_histogram[nth_bin] += 1
else:
neg_histogram[nth_bin] += 1
accumulated_neg = 0
satisfied_pair = 0
for i in range(n_bins):
satisfied_pair += (pos_histogram[i]*accumulated_neg + pos_histogram[i]*neg_histogram[i]*0.5)
accumulated_neg += neg_histogram[i]
return satisfied_pair / float(total_case)
y = np.array([1,0,0,0,1,0,1,0,])
pred = np.array([0.9, 0.8, 0.3, 0.1,0.4,0.9,0.66,0.7])
print("----auc is :",auc_calculate(y,pred))
3. AUROC (Area Under the Receiver Operating Characteristic curve)
大多数时候,AUC都是指AUROC,这是一个不好地做法,AUC有歧义(可能是任何曲线),而AUROC没有歧义。
其余部分,与AUC一致。