AUC兩種計算方式
阿新 • • 發佈:2021-09-04
1.通過ROC曲線面積計算AUC
AUC(Area Under Curve)被定義為ROC曲線下的面積。
ROC 曲線橫座標:假正率=FPR=FP/N: 預測為負 and 實際為正 / 實際為負
ROC 曲線縱座標:真正率=TPR= TP/P :預測為正 and 實際為正 / 實際為正
注意:有相同預估值時,需要等當前預估值作為閾值的所有 tp,fp 算完,再更新最終 auc
def calcAUC_byRocArea(label,pred): P = 0.0 N = 0.0 TP = 0.0 FP = 0.0 TPR = 0.0 FPR = 0.0 LAST_TRP = 0.0 LAST_FPR = 0.0 auc = 0.0 for l in label: if l == 0: N+=1 else: P+=1 sample = zip(label,pred) sample_sorted = sorted(sample,key=lambda x: -x[1]) for i,info in enumerate(sample_sorted): l,p = info if l == 1: TP+=1 else: FP+=1 if i !=0 and i+1 < len(sample) and p == sample_sorted[i+1][1]: continue TPR = TP/P FPR = FP/N auc+=0.5*(TPR+LAST_TRP)*(FPR-LAST_FPR) LAST_FPR=FPR LAST_TRP=TPR return auc
2.通過計算概率計算AUC
AUC還有一種解釋就是任取一對正負樣本,正樣本的預測值大於負樣本的預測值的概率。
2.1 暴力 時間複雜度 o(n2)
(1)遍歷 label, 選出正樣本、負樣本。
(2)遍歷正負樣本 pair,記錄正樣本 pred> 負樣本 pred 的個數為 cnt
(3) auc = cnt / 正樣本個數* 負樣本個數。
1 from sklearn.metrics import roc_auc_score 2 import numpy as np 3 4 def calcAUC_byProb(label,pred): 5 pos_porb = []6 neg_prob = [] 7 for i in range(len(label)): 8 if label[i] == 1: 9 pos_porb.append(pred[i]) 10 elif label[i] == 0: 11 neg_prob.append(pred[i]) 12 cnt = 0.0 13 for p in pos_porb: 14 for n in neg_prob: 15 if (p>n): 16 cnt+=1 17elif(p == n): 18 cnt+=0.5 19 return cnt / float(len(pos_porb)*len(neg_prob)) 20 21 y = np.array([1, 1, 1, 0,0]) 22 pred = np.array([0.6,0.3, 0.5 ,0.2,0.4]) 23 print("sklearn auc:",roc_auc_score(y, pred)) 24 #print("my auc calc by area:", calcAUC_byRocArea(y, pred)) 25 print("my auc calc by prob:", calcAUC_byProb(y, pred))
2.2 動態規劃,時間複雜度0(nlogn)
(1)按照預估值降序,組成 pair。
(2)遍歷pair, 如果 label==1,記錄正樣本個數 pos,
如果 label==0, 對於當前樣本來說,前面所有的正樣本個數pos就是 當前樣本與所有正樣本預估值大於當前負樣本預估值的個數。
(3)auc = pos / (pos *n-pos)
1 def calcAUC_byProb(label,pred): 2 sample = zip(label,pred) 3 sample_sorted = sorted(sample,key=lambda x: -x[1]) 4 pos = 0 5 cnt = 0 6 last_pred = 0 7 print(sample_sorted) 8 for i in range(len(sample_sorted)): 9 l,p = sample_sorted[i] 10 if l == 1: 11 pos+=1 12 elif l == 0: 13 cnt += pos 14 if (i!=0 and last_pred ==p): 15 cnt-=0.5 16 last_pred = p 17 negs = len(label) - pos 18 print (cnt,pos,negs) 19 return float(cnt) / float(pos*negs)