混淆矩阵

python查全率和查准率 查全率与查准率公式_python查全率和查准率

TP(true positive):真正例

FP(false positive):假正例

FN(false negative):假反例

TN(true negative):真反例

 

查准率(精确率)和查全率(召回率)

P=TP/(TP+FP),R=TP/(TP+FN)

 

准确率

 

准确率的定义是预测正确的结果占总样本的百分比,其公式如下:

 

准确率=(TP+TN)/(TP+TN+FP+FN)

虽然准确率可以判断总的正确率,但是在样本不平衡的情况下,并不能作为很好的指标来衡量结果。举个简单的例子,比如在一个总样本中,正样本占90%,负样本占10%,样本是严重不平衡的。对于这种情况,我们只需要将全部样本预测为正样本即可得到90%的高准确率,但实际上我们并没有很用心的分类,只是随便无脑一分而已。这就说明了:由于样本不平衡的问题,导致了得到的高准确率结果含有很大的水分。即如果样本不平衡,准确率就会失效。

 

 

P-R曲线:

查准率和查全率曲线(纵横)

python查全率和查准率 查全率与查准率公式_正例_02

 

F1值

 

F1=(2*P*R)/(P+R),  $\frac{1}{{F1}} = \frac{1}{2} \cdot \left( {\frac{1}{P} + \frac{1}{R}} \right)$,是P,R的调和平均

F1值就是查准率和查全率间的一个均衡。

 

ROC曲线

ROC:TPR(真正例率)-FPR(假正例率)

TPR=TP/(TP+FN),预测为正样本的正样本占真的正样本的比例,也就是正样本的召回率。

FPR=FP/(TN+FP),预测为正样本的负样本占真的负样本的比例,也就是负样本的误分率。

我们发现TPR和FPR分别是基于实际表现1和0出发的,也就是说它们分别在实际的正样本和负样本中来观察相关概率问题。正因为如此,所以无论样本是否平衡,都不会被影响。还是拿之前的例子,总样本中,90%是正样本,10%是负样本。我们知道用准确率是有水分的,但是用TPR和FPR不一样。这里,TPR只关注90%正样本中有多少是被真正覆盖的,而与那10%毫无关系,同理,FPR只关注10%负样本中有多少是被错误覆盖的,也与那90%毫无关系,所以可以看出:如果我们从实际表现的各个结果角度出发,就可以避免样本不平衡的问题了,这也是为什么选用TPR和FPR作为ROC/AUC的指标的原因。

python查全率和查准率 查全率与查准率公式_python查全率和查准率_03

 

AUC面积

AUC:ROC曲线下面积,AUC可理解为预测得到正样本的概率大于负样本概率的概率(AUC可以看作随机选取一对正负样本,其中正样本的得分大于负样本得分的概率)

 

AUC计算方法1:

python查全率和查准率 查全率与查准率公式_机器学习_04

方法2:

python查全率和查准率 查全率与查准率公式_反例_05

 

问题

1.  PR曲线和ROC曲线的区别

当正负样本的分布发生变化时,ROC曲线的形状能够基本保持不变,而PR曲线的形状一般会发生激烈变化。

python查全率和查准率 查全率与查准率公式_python查全率和查准率_06

 

auc计算代码

方法1: 按积分的方法直接算roc曲线下的面积

时间复杂度 nlogn

计算公式如下:

python查全率和查准率 查全率与查准率公式_反例_07

 

x, y 分别表示 roc曲线上的FPR、TPR

初始时把阈值定为 max(pred) +1, 后面的阈值就是 pred 从大到小排序

 

方法2: 按概率的方法计算auc

优化后的时间复杂度也是 nlogn

import numpy as np
from sklearn.metrics import roc_auc_score

def calcAUC_byRocArea(labels,probs):
    P = 0
    N = 0
    for i in labels:
        if (i == 1):
            P += 1
        else:
            N += 1
    TP = 0
    FP = 0
    TPR_last = 0
    FPR_last = 0
    AUC = 0
    pair = zip(probs, labels)
    pair = sorted(pair, key=lambda x:x[0], reverse=True)
    i = 0
    while i < len(pair):
        if (pair[i][1] == 1):
            TP += 1
        else:
            FP += 1
        ### maybe have the same probs
        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

def calcAUC_byProb(labels, probs):
    pair = zip(probs, labels)
    pair = sorted(pair, key=lambda x:x[0], reverse=False)
    neg_prob = []
    pos_prob = []
    for prob, label in pair:
        if label == 1:
            pos_prob.append(prob)
        else:
            neg_prob.append(prob)
    
    num = 0
    k = 0
    j = 0
    eq = 0
    for i in range(len(pos_prob)):
        if i > 0 and pos_prob[i] == pos_prob[i-1]:
            num += k + 0.5 * eq
            continue
        else:
            k += eq
            eq = 0
        while j < len(neg_prob):
            if pos_prob[i] > neg_prob[j]:
                k += 1
            elif pos_prob[i] == neg_prob[j]:
                eq += 1
            else:
                break
            j += 1
        num += k + 0.5 * eq
    return num / (len(pos_prob) * len(neg_prob))

# y = np.array([1, 1, 2, 2])
# pred = np.array([0.1, 0.4, 0.35, 0.8])
# fpr, tpr, thresholds = metrics.roc_curve(y, pred, pos_label=2)
# print(fpr)
# print(tpr)
# print(thresholds)
# print(metrics.auc(fpr, tpr))

y = [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0]
pred = [0.1, 0.4, 0.5 ,0.6, 0.35, 0.8, 0.9, 0.4, 0.25, 0.5, 0.2, 0.2, 0.2, 0.5, 0.8]

print(calcAUC_byRocArea(y, pred))
print(calcAUC_byProb(y, pred))
print("sklearn auc:",roc_auc_score(y, pred))