方法一
用指示函数表示上式中正样本预测值大于负样本预测值的正负样本对,则得到
p表示预测得分。
在给出的例子中,包含有2个正样本(A, B)和3个负样本(C, D, E),因此一共有6个(2*3)正负样本对,即公式中分母为6。
接下来计算公式中的分子,即每个正负样本对的指示函数值:
- 以A为正样本形成的正负样本对为(A, C), (A, D), (A, E),指示函数值分别为1,0.5,0;
- 以B为正样本形成的正负样本对为(B, C), (B, D), (B, E),指示函数值分别为1,1,1。
这种方法计算AUC的时间复杂度为O(P*N)
方法二
用方法1计算AUC易于理解,但需要对所有样本对计算指示函数值,有没有不需要对所有样本对遍历的方法?
AUC计算的关键是找到所有正样本预测值大于负样本预测值的正负样本对。
- 如果引入排序,则大小关系就可以确定;
- 如果有正样本的排序序号,则可以每一个正样本有多少样本的分数比他低(这其中包括正负样本对,也包括正正样本对),若减去正正样本对数量就是AUC计算需要的正负样本对。
举例来说:
在上面的例子中出现了正样本A与负样本D得分相等的情况,这时候A排序值由相同得分的排序值算平均值,即(2+3)/2=2.5。
这样,2.5+5 = 7.5(说明一共有7.5个样本对,正样本打分高于其他样本),然后7.5中还包括正正样本对,大小为M(M+1)/2, 则所有正样本中,正样本大于负样本打分的样本对有7.5-2(2+1)/2=4.5。分母不变=2*3
则auc为:
代码
import numpy as np
from sklearn.metrics import roc_auc_score
# python sklearn包计算auc
def get_auc(y_labels, y_scores):
auc = roc_auc_score(y_labels, y_scores)
print('AUC calculated by sklearn tool is {}'.format(auc))
return auc
# 方法1计算auc
def calculate_auc_func1(y_labels, y_scores):
pos_sample_ids = [i for i in range(len(y_labels)) if y_labels[i] == 1]
neg_sample_ids = [i for i in range(len(y_labels)) if y_labels[i] == 0]
sum_indicator_value = 0
for i in pos_sample_ids:
for j in neg_sample_ids:
if y_scores[i] > y_scores[j]:
sum_indicator_value += 1
elif y_scores[i] == y_scores[j]:
sum_indicator_value += 0.5
auc = sum_indicator_value/(len(pos_sample_ids) * len(neg_sample_ids))
print('AUC calculated by function1 is {:.2f}'.format(auc))
return auc
# 方法2计算auc, 当预测分相同时,未按照定义使用排序值的均值,而是直接使用排序值,当数据量大时,对auc影响小
def calculate_auc_func2(y_labels, y_scores):
samples = list(zip(y_scores, y_labels))
rank = [(values2, values1) for values1, values2 in sorted(samples, key=lambda x:x[0])]
pos_rank = [i+1 for i in range(len(rank)) if rank[i][0] == 1]
pos_cnt = np.sum(y_labels == 1)
neg_cnt = np.sum(y_labels == 0)
auc = (np.sum(pos_rank) - pos_cnt*(pos_cnt+1)/2) / (pos_cnt*neg_cnt)
print('AUC calculated by function2 is {:.2f}'.format(auc))
return auc
if __name__ == '__main__':
y_labels = np.array([1, 1, 0, 0, 0])
y_scores = np.array([0.4, 0.8, 0.2, 0.4, 0.5])
get_auc(y_labels, y_scores)
calculate_auc_func1(y_labels, y_scores)
calculate_auc_func2(y_labels, y_scores)