混淆矩阵
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曲线:
查准率和查全率曲线(纵横)
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的指标的原因。
AUC面积
AUC:ROC曲线下面积,AUC可理解为预测得到正样本的概率大于负样本概率的概率(AUC可以看作随机选取一对正负样本,其中正样本的得分大于负样本得分的概率)
AUC计算方法1:
方法2:
问题
1. PR曲线和ROC曲线的区别
当正负样本的分布发生变化时,ROC曲线的形状能够基本保持不变,而PR曲线的形状一般会发生激烈变化。
auc计算代码
方法1: 按积分的方法直接算roc曲线下的面积
时间复杂度 nlogn
计算公式如下:
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))