机器学习篇-指标:AUC
AUC是什么東西?
AUC是一個模型評價指標,只能夠用于二分類模型的評價,對于二分類模型來說還有很多其他的評價指標:
比如:logloss,accuracy,precision
在上述的評價指標當中,數據挖掘類比賽中,AUC和logloss是比較常見的模型評價指標
那么問題來了||ヽ( ̄▽ ̄)ノミ|Ю為啥是AUC和logloss?
因為很多機器學習的模型對分類問題的預測結果都是概率,如果要計算accuracy的話,需要先將概率轉換成類別,這就需要手動設置一個閾值,如果對一個樣本的預測概率高于這個預測,就把這個樣本放進一個類別當中,如果低于這個閾值,就放在另一個類別當中,閾值在很大程度上影響了accuracy的計算
使用AUC或者logloss的好處就是可以避免將預測概率轉換成類別
AUC: Area under curve
字面理解:某條曲線下面區域的面積
問題來了,到底是哪一條曲線?
曲線的名字叫做:ROC曲線
ROC曲線講解
(該內容來自于維基百科)
ROC分析的是二元分類模型,也就是輸出結果只有兩種類別的模型(垃圾郵件/非垃圾郵件)
當觀測量的結果是一個連續值的時候,類與類的邊界必須用一個閾值threshold來界定
舉例來說,用血壓值來檢測一個人是否有高血壓,測出的血壓值是連續的實數(從0~200都有可能),以收縮壓140/舒張壓90為閾值,閾值以上便診斷為有高血壓,閾值未滿者診斷為無高血壓。二元分類模型的個案預測有四種結局:P:positive N:negative
- 真陽性(TP):診斷為有,實際上也有高血壓。
- 偽陽性(FP):診斷為有,實際卻沒有高血壓。
- 真陰性(TN):診斷為沒有,實際上也沒有高血壓。
- 偽陰性(FN):診斷為沒有,實際卻有高血壓。
這四種結局可以畫成2 × 2的混淆矩陣:
ROC空間將偽陽性率FPR定義為X軸,將真陽性率TPR定義為Y軸
TPR:在所有實際為陽性的樣本中,被正確地判斷為陽性之比率。
FPR:在所有實際為陰性的樣本中,被錯誤地判斷為陽性之比率。
給定一個二元分類模型和它的閾值,就能從所有樣本的(陽性/陰性)真實值和預測值計算出一個 (X=FPR, Y=TPR) 座標點。
從 (0, 0) 到 (1,1) 的對角線將ROC空間劃分為左上/右下兩個區域,在這條線的以上的點代表了一個好的分類結果(勝過隨機分類),而在這條線以下的點代表了差的分類結果(劣于隨機分類)。
完美的預測是一個在左上角的點,在ROC空間座標 (0,1)點,X=0 代表著沒有偽陽性,Y=1 代表著沒有偽陰性(所有的陽性都是真陽性);也就是說,不管分類器輸出結果是陽性或陰性,都是100%正確。一個隨機的預測會得到位于從 (0, 0) 到 (1, 1) 對角線(也叫無識別率線)上的一個點;最直觀的隨機預測的例子就是拋硬幣。
讓我們來看在實際有100個陽性和100個陰性的案例時,四種預測方法(可能是四種分類器,或是同一分類器的四種閾值設定)的結果差異:
將這4種結果畫在ROC空間里:
**離左上角越近的點預測(診斷)準確率越高。**離右下角越近的點,預測越不準。
在A、B、C三者當中,最好的結果是A方法。
B方法的結果位于隨機猜測線(對角線)上,在例子中我們可以看到B的準確度是50%。
C雖然預測準確度最差,甚至劣于隨機分類,也就是低于0.5(低于對角線)。然而,當將C以 (0.5, 0.5) 為中點作一個鏡像后,C’的結果甚至要比A還要好。這個作鏡像的方法,簡單說,不管C(或任何ROC點低于對角線的情況)預測了什么,就做相反的結論。
上述ROC空間里的單點,是給定分類模型且給定閾值后得出的。但同一個二元分類模型的閾值可能設定為高或低,每種閾值的設定會得出不同的FPR和TPR。
將同一模型每個閾值 的 (FPR, TPR) 座標都畫在ROC空間里,就成為特定模型的ROC曲線。
在同一個分類器之內,閾值的不同設定對ROC曲線的影響,仍有一些規律可循:
-
當閾值設定為最高時,亦即所有樣本都被預測為陰性,沒有樣本被預測為陽性,此時在偽陽性率 FPR = FP / ( FP + TN ) 算式中的 FP = 0,所以 FPR = 0%。同時在真陽性率(TPR)算式中, TPR = TP / ( TP + FN ) 算式中的 TP = 0,所以 TPR = 0%
–> 當閾值設定為最高時,必得出ROC座標系左下角的點 (0, 0)。 -
當閾值設定為最低時,亦即所有樣本都被預測為陽性,沒有樣本被預測為陰性,此時在偽陽性率FPR = FP / ( FP + TN ) 算式中的 TN = 0,所以 FPR = 100%。同時在真陽性率 TPR = TP / ( TP + FN ) 算式中的 FN = 0,所以TPR=100%
–>當閾值設定為最低時,必得出ROC座標系右上角的點 (1, 1)。
因為TP、FP、TN、FN都是累積次數,TN和FN隨著閾值調低而減少(或持平),TP和FP隨著閾值調低而增加(或持平),所以FPR和TPR皆必隨著閾值調低而增加(或持平)。
–>隨著閾值調低,ROC點 往右上(或右/或上)移動,或不動;但絕不會往左下(或左/或下)移動。
曲線下面積(AUC)
在比較不同的分類模型時,可以將每個模型的ROC曲線都畫出來,比較曲線下面積做為模型優劣的指標。
意義
ROC曲線下方的面積(英語:Area under the Curve of ROC (AUC ROC)),其意義是:
因為是在1x1的方格里求面積,AUC必在0~1之間。
假設閾值以上是陽性,以下是陰性;
若隨機抽取一個陽性樣本和一個陰性樣本,分類器正確判斷陽性樣本的值高于陰性樣本之機率=AUC
簡單說:AUC值越大的分類器,正確率越高。
從AUC判斷分類器(預測模型)優劣的標準:
AUC = 1,是完美分類器,采用這個預測模型時,存在至少一個閾值能得出完美預測。絕大多數預測的場合,不存在完美分類器。
0.5 < AUC < 1,優于隨機猜測。這個分類器(模型)妥善設定閾值的話,能有預測價值。
AUC = 0.5,跟隨機猜測一樣(例:丟銅板),模型沒有預測價值。
AUC < 0.5,比隨機猜測還差;但只要總是反預測而行,就優于隨機猜測。
計算
AUC的計算有兩種方式,都是以逼近法求近似值。
AUC為什么可以衡量分類的效果?
- AUC就是從所有1樣本中隨機選取一個樣本,從所有0樣本中隨機選取一個樣本,然后根據你的分類器對兩個隨機樣本進行預測,把1樣本預測為1的概率為p1,把0樣本預測為1的概率為p2,p1>p2的概率就是AUC。所以AUC應該反映的是分類器對樣本的排序能力,另外,AUC對樣本類別是否均衡并不敏感,這也是不均衡樣本通常采用AUC評價分類性能的原因
根據上面的推斷,那么隨機抽取一個樣本,對應每一潛在可能值X都有對應一個判定正樣本的概率P。
對一批已知正負的樣本集合進行分類,按照預測概率從高到低進行排序,
對于正樣本中概率最高的,排序為rank_1,
比它概率小的有M-1個正樣本(M為正樣本個數),(ranl_1-M)個負樣本。
正樣本中概率第二高的,排序為rank_2,
比它概率小的有M-2個正樣本,(rank_2-(M-1))個負樣本,
以此類推,正樣本中概率最小的,排序為rank_M,
比它概率小的有0個正樣本,(rank_M-1)個負樣本。
總共有M*N個正負樣本對,把所有比較中正樣本概率大于負樣本概率的例子都算上,
得到公式:
就是正樣本概率大于負樣本概率的可能性,將上述結果化簡之后:
上述結果就是,AUC公式
AUC是現在分類模型中,特別是二分類模型使用的主要離線評測指標之一,相比于準確率,召回率,AUC有一個獨特的優勢,就是不管具體的得分,只關注于排序結果,這使得它特別適用于排序問題的效果評估
根據上面的公式求解AUC
首先對score從大到小排序,然后令最大score對應的sample的rank值為n,第二大score對應sample的rank值為n-1,以此類推從n到1。然后把所有的正類樣本的rank相加,再減去正類樣本的score為最小的那M個值的情況。得到的結果就是有多少對正類樣本的score值大于負類樣本的score值,最后再除以M×N即可。**值得注意的是,當存在score相等的時候,對于score相等的樣本,需要賦予相同的rank值(無論這個相等的score是出現在同類樣本還是不同類的樣本之間,都需要這樣處理)。**具體操作就是再把所有這些score相等的樣本 的rank取平均。然后再使用上述公式。此公式描述如下:
def naive_auc(labels,preds):"""最簡單粗暴的方法先排序,然后統計有多少正負樣本對滿足:正樣本預測值>負樣本預測值, 再除以總的正負樣本對個數。復雜度 O(NlogN), N為樣本數"""n_pos = sum(labels)n_neg = len(labels) - n_postotal_pair = n_pos * n_neglabels_preds = zip(labels,preds)labels_preds = sorted(labels_preds,key=lambda x:x[1])//從小到大,倒序計算accumulated_neg = 0satisfied_pair = 0for i in range(len(labels_preds)):if labels_preds[i][0] == 1:satisfied_pair += accumulated_negelse:accumulated_neg += 1return satisfied_pair / float(total_pair)接下來還可以采用進一步加速的方法:
使用近似方式,將預測值分桶,對正負樣本分別構建直方圖,再統計滿足條件的正負樣本對
關于AUC還有一個很有趣的性質,它和Wilcoxon-Mann-Witney Test類似(可以去google搜一下),而Wilcoxon-Mann-Witney Test就是**測試任意給一個正類樣本和一個負類樣本,正類樣本的score有多大的概率大于負類樣本的score。**有了這個定義,就可以得到了另外一中計算AUC的方法:計算出這個概率值。我們知道,在有限樣本中我們常用的得到概率的辦法就是通過頻率來估計之。這種估計隨著樣本規模的擴大而逐漸逼近真實值。樣本數越多,計算的AUC越準確類似,也和計算積分的時候,小區間劃分的越細,計算的越準確是同樣的道理。具體來說就是: 統計一下所有的 M×N(M為正類樣本的數目,N為負類樣本的數目)個正負樣本對中,有多少個組中的正樣本的score大于負樣本的score。當二元組中正負樣本的 score相等的時候,按照0.5計算。然后除以MN。實現這個方法的復雜度為O(n^2 )。n為樣本數(即n=M+N),公式表示如下:
但是上述方法的問題在于:
預測值大多不是均勻分布在0-1之間的,分布特別不平衡的話,均勻分出來的桶就不太好,
采用頻率進行劃分桶,(均勻劃分,等頻劃分)
進一步的嘗試MapReduce如何計算AUC
MAP階段:統計直方圖
Reduce階段:計算AUC的結果
上述完整代碼:
# coding=utf-8 # auc值的大小可以理解為: 隨機抽一個正樣本和一個負樣本,正樣本預測值比負樣本大的概率 # 根據這個定義,我們可以自己實現計算aucimport random import timedef timeit(func):"""裝飾器,計算函數執行時間"""def wrapper(*args, **kwargs):time_start = time.time()result = func(*args, **kwargs)time_end = time.time()exec_time = time_end - time_startprint "{function} exec time: {time}s".format(function=func.__name__,time=exec_time)return resultreturn wrapperdef gen_label_pred(n_sample):"""隨機生成n個樣本的標簽和預測值"""labels = [random.randint(0,1) for _ in range(n_sample)]preds = [random.random() for _ in range(n_sample)]return labels,preds@timeit def naive_auc(labels,preds):"""最簡單粗暴的方法先排序,然后統計有多少正負樣本對滿足:正樣本預測值>負樣本預測值, 再除以總的正負樣本對個數復雜度 O(NlogN), N為樣本數"""n_pos = sum(labels)n_neg = len(labels) - n_postotal_pair = n_pos * n_neglabels_preds = zip(labels,preds)labels_preds = sorted(labels_preds,key=lambda x:x[1])accumulated_neg = 0satisfied_pair = 0for i in range(len(labels_preds)):if labels_preds[i][0] == 1:satisfied_pair += accumulated_negelse:accumulated_neg += 1return satisfied_pair / float(total_pair)@timeit def approximate_auc(labels,preds,n_bins=100):"""近似方法,將預測值分桶(n_bins),對正負樣本分別構建直方圖,再統計滿足條件的正負樣本對復雜度 O(N)這種方法有什么缺點?怎么分桶?"""n_pos = sum(labels)n_neg = len(labels) - n_postotal_pair = n_pos * n_negpos_histogram = [0 for _ in range(n_bins)]neg_histogram = [0 for _ in range(n_bins)]bin_width = 1.0 / n_binsfor i in range(len(labels)):nth_bin = int(preds[i]/bin_width)if labels[i]==1:pos_histogram[nth_bin] += 1else:neg_histogram[nth_bin] += 1accumulated_neg = 0satisfied_pair = 0for i in range(n_bins):satisfied_pair += (pos_histogram[i]*accumulated_neg + pos_histogram[i]*neg_histogram[i]*0.5)accumulated_neg += neg_histogram[i]return satisfied_pair / float(total_pair)# 思考:mapreduce版本的auc該怎么寫if __name__ == "__main__":labels,preds = gen_label_pred(10000000)naive_auc_rst = naive_auc(labels,preds)approximate_auc_rst = approximate_auc(labels,preds)print "naive auc result:{},approximate auc result:{}".format(naive_auc_rst,approximate_auc_rst)"""naive_auc exec time: 31.7306630611sapproximate_auc exec time: 2.32403683662snaive auc result:0.500267265728,approximate auc result:0.50026516844"""總結
以上是生活随笔為你收集整理的机器学习篇-指标:AUC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【网络】浏览器输入URL到展示页面全过程
- 下一篇: Python3之configparser