ROC曲线、AUC、PR曲线等

二分类模型的样本预测有四种可能性:

  • 真阳性(TP):预测为T,实际为T;
  • 假阳性(FP):预测为T,实际为F;(第一型错误)
  • 真阴性(TN):预测为F,实际为F;
  • 假阴性(FN):预测为F,实际为T。(第二型错误)

引申出其他概念:

  • 真阳性率:TPR = TP / P = TP / (TP + FN)
  • 假阳性率:FPR = FP / N = FP / (FP + TN)
  • 准确率:ACC = (TP + TN) / (P + N)
  • 精确率:Precision = TP / (TP + FP)
  • 召回率:Recall = TP / (TP + FN)
  • F1:1/F1 = (1/Precision + 1/Recall) / 2

ROC空间把FPR定位为x轴,TPR定义为y轴。给定一个二分类模型和阈值,就能从所有样本的真实值和预测值中得到一个(x=FPR, y=TPR)坐标,坐标连成一条曲线。y=x曲线代表随机分类的结果。在曲线更上方代表分类结果更好,在更下方代表更差。一个完美的预测是在左上角的(0,1)点。

ROC曲线下的面积为AUC。AUC代表:随机抽取一个阳性样本和阴性样本,阳性样本的预测值高于阴性样本的概率。

AUC只关注正负样本间的排序,不受类别样本量不均衡影响,对推荐排序模型很适用。但同时也存在以下问题:
(1) 忽略了预测的概率值,例如对"1"类样本预测为0.51,对"0"类样本预测为0.49,此时AUC为1,但预测结果与真实标签差距很大,输入稍有扰动就会产生错误的预测结果。
(2) 无法得到模型误差的分布信息,比如正样本内部,负样本内部的排序情况和误差分布。另外对两类错误同等看待。
(3) 同一AUC的不同形状曲线,代表两个模型在取不同阈值的预测能力是不同的。
因此还需要综合召回率、精确率、ROC曲线、PR曲线、TPR、FPR等指标观察模型的能力。

PR曲线以recall为x轴,precision为y轴,通过每个阈值得到一个坐标连线而成。当正负样本差距不大的情况下,ROC和PR的趋势是差不多的,但是当负样本很多的时候,两者就截然不同了,ROC效果依然看似很好,但是PR上反映效果一般。比如就1个正例,100个负例,那么基本上TPR可能一直维持在1,然后突然降到0。

AUC代码实现:
按roc曲线下面积计算

def cal_auc(labels, probs):
    P, N = 0, 0
    for label in labels:
        if label == 1:
            P += 1
        else:
            N += 1
    TP, FP, TPR_last, FPR_last = 0, 0, 0, 0
    AUC = 0
    pair = zip(probs, labels)
    pair = sorted(pair, key=lambda x:x[0], reverse=True)
    i = 0 #i的位置为阈值
    while i < len(pair):
        if (pair[i][1] == 1):
            TP += 1
        else:
            FP += 1
        #相同预测值处理
        while (i + 1 < len(pair) and pair[i][0] == pair[i+1][0]):
            i += 1
            if (pair[i][1] == 1):
                TP += 1
            else:
                FP += 1
        TPR = TP / P
        FPR = FP / N
        AUC += 0.5 * (TPR + TPR_last) * (FPR - FPR_last) #梯形
        TPR_last = TPR
        FPR_last = FPR
        i += 1
    return AUC

按auc的物理含义计算:

def cal_auc(labels, probs):
    P, N = 0, 0
    pos_prob, neg_prob = [], []
    for i, label in enumerate(labels):
        if (label == 1):
            P += 1
            pos_prob.append(probs[i])
        else:
            N += 1
            neg_prob.append(probs[i])
    number = 0 #正样本预测值大于负样本的样本对数量
    for pos in pos_prob:
        for neg in neg_prob:
            if (pos > neg):
                number += 1
            elif (pos == neg): # 正负样本预测值相同的记0.5
                number += 0.5
    return number / (N * P)

你可能感兴趣的:(ROC曲线、AUC、PR曲线等)