1. 程式人生 > >機器學習之類別不平衡問題 (2) —— ROC和PR曲線

機器學習之類別不平衡問題 (2) —— ROC和PR曲線

完整程式碼


ROC曲線和PR(Precision - Recall)曲線皆為類別不平衡問題中常用的評估方法,二者既有相同也有不同點。本篇文章先給出ROC曲線的概述、實現方法、優缺點,再闡述PR曲線的各項特點,最後給出兩種方法各自的使用場景。

ROC曲線

這裡寫圖片描述
ROC曲線常用於二分類問題中的模型比較,主要表現為一種真正例率 (TPR) 和假正例率 (FPR) 的權衡。具體方法是在不同的分類閾值 (threshold) 設定下分別以TPR和FPR為縱、橫軸作圖。由ROC曲線的兩個指標,TPR=TPP=TPTP+FNFPR=FP

N=FPFP+TN 可以看出,當一個樣本被分類器判為正例,若其本身是正例,則TPR增加;若其本身是負例,則FPR增加,因此ROC曲線可以看作是隨著閾值的不斷移動,所有樣本中正例與負例之間的“對抗”。曲線越靠近左上角,意味著越多的正例優先於負例,模型的整體表現也就越好。

AUC (Area Under the Curve)

這裡寫圖片描述
先看一下ROC曲線中的隨機線,圖中[0,0]到[1,1]的虛線即為隨機線,該線上所有的點都表示該閾值下TPR=FPR,根據定義,TPR=TPP,表示所有正例中被預測為正例的概率;FPR=FPN,表示所有負例中被被預測為正例的概率。若二者相等,意味著無論一個樣本本身是正例還是負例,分類器預測其為正例的概率是一樣的,這等同於隨機猜測(注意這裡的“隨機”不是像拋硬幣那樣50%正面50%反面的那種隨機)。

上圖中B點就是一個隨機點,無論是樣本數量和類別如何變化,始終將75%的樣本分為正例。

ROC曲線圍成的面積 (即AUC)可以解讀為:從所有正例中隨機選取一個樣本A,再從所有負例中隨機選取一個樣本B,分類器將A判為正例的概率比將B判為正例的概率大的可能性。可以看到位於隨機線上方的點(如圖中的A點)被認為好於隨機猜測。在這樣的點上TPR總大於FPR,意為正例被判為正例的概率大於負例被判為正例的概率。

從另一個角度看,由於畫ROC曲線時都是先將所有樣本按分類器的預測概率排序,所以AUC反映的是分類器對樣本的排序能力,依照上面的例子就是A排在B前面的概率。AUC越大,自然排序能力越好,即分類器將越多的正例排在負例之前。


ROC曲線的繪製方法:假設有P個正例,N個反例,首先拿到分類器對於每個樣本預測為正例的概率,根據概率對所有樣本進行逆序排列,然後將分類閾值設為最大,即把所有樣本均預測為反例,此時圖上的點為 (0,0)。然後將分類閾值依次設為每個樣本的預測概率,即依次將每個樣本劃分為正例,如果該樣本為真正例,則TP+1,即TPR + 1P ; 如果該樣本為負例,則FP+1,即FPR + 1N。最後的到所有樣本點的TPR和FPR值,用線段相連。

下面進行實現,先模擬生成一個正例:負例=10:1的資料集,用PCA降到2維進行視覺化:

X,y = make_classification(n_samples=2000, n_features=10, n_informative=4,
                         n_redundant=1, n_classes=2, n_clusters_per_class=1,
                         weights=[0.9,0.1], flip_y=0.1, random_state=2018)

sns.lmplot("pca_a","pca_b",data=X_pca, hue="y", fit_reg=False, markers=["o","x"],size=8,aspect=1.5,legend=False)
plt.legend(fontsize=20,bbox_to_anchor=(0.98, 0.6),edgecolor ='r')   
plt.xlabel("axis_1",fontsize=17)
plt.ylabel("axis_2",fontsize=17)

這裡寫圖片描述

將資料分成訓練集和測試集,使用Logistic Regression和Random Forest作圖:

kf = StratifiedKFold(n_splits=2, random_state=42)
for train_index, test_index in kf.split(X,y):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index] 

lr = LogisticRegression()
lr.fit(X_train,y_train)
pos_prob_lr = lr.predict_proba(X_test)[:,1]    # Logistic Regression的正例預測概率

rf = RandomForestClassifier(random_state=42)
rf.fit(X_train,y_train)
pos_prob_rf = rf.predict_proba(X_test)[:,1]    # Random Forest的正例預測概率

def get_roc(pos_prob,y_true):
    pos = y_true[y_true==1]
    neg = y_true[y_true==0]
    threshold = np.sort(pos_prob)[::-1]        # 按概率大小逆序排列
    y = y_true[pos_prob.argsort()[::-1]]
    tpr_all = [0] ; fpr_all = [0]
    tpr = 0 ; fpr = 0
    x_step = 1/float(len(neg))
    y_step = 1/float(len(pos))
    y_sum = 0                                  # 用於計算AUC
    for i in range(len(threshold)):
        if y[i] == 1:
            tpr += y_step
            tpr_all.append(tpr)
            fpr_all.append(fpr)
        else:
            fpr += x_step
            fpr_all.append(fpr)
            tpr_all.append(tpr)
            y_sum += tpr
    return tpr_all,fpr_all,y_sum*x_step         # 獲得總體TPR,FPR和相應的AUC

tpr_lr,fpr_lr,auc_lr = get_roc(pos_prob_lr,y_test)  
tpr_rf,fpr_rf,auc_rf = get_roc(pos_prob_rf,y_test)

plt.figure(figsize=(10,6))
plt.plot(fpr_lr,tpr_lr,label="Logistic Regression (AUC: {:.3f})".format(auc_lr),linewidth=2)
plt.plot(fpr_rf,tpr_rf,'g',label="Random Forest (AUC: {:.3f})".format(auc_rf),linewidth=2)
plt.xlabel("False Positive Rate",fontsize=16)
plt.ylabel("True Positive Rate",fontsize=16)
plt.title("ROC Curve",fontsize=16)
plt.legend(loc="lower right",fontsize=16)

這裡寫圖片描述

ROC曲線的優點

放一張混淆矩陣圖可能看得更清楚一點:

這裡寫圖片描述

  1. 兼顧正例和負例的權衡。因為TPR聚焦於正例,FPR聚焦於與負例,使其成為一個比較均衡的評估方法。

  2. ROC曲線選用的兩個指標,TPR=TPP=TPTP+FNFPR=FPN=FPFP+TN,都不依賴於具體的類別分佈。

    注意TPR用到的TP和FN同屬P列,FPR用到的FP和TN同屬N列,所以即使P或N的整體數量發生了改變,也不會影響到另一列。也就是說,即使正例與負例的比例發生了很大變化,ROC曲線也不會產生大的變化,而像Precision使用的TP和FP就分屬兩列,則易受類別分佈改變的影響。

    參考文獻 [1] 中舉了個例子,負例增加了10倍,ROC曲線沒有改變,而PR曲線則變了很多。作者認為這是ROC曲線的優點,即具有魯棒性,在類別分佈發生明顯改變的情況下依然能客觀地識別出較好的分類器。

這裡寫圖片描述

下面我們來驗證一下是不是這樣:

X_test_dup = np.vstack((X_test,X_test[y_test==0],X_test[y_test==0],X_test[y_test==0],X_test[y_test==0],X_test[y_test==0],X_test[y_test==0],X_test[y_test==0],X_test[y_test==0],X_test[y_test==0]))
y_test_dup = np.array(y_test.tolist() + y_test[y_test==0].tolist()*9)   # 10x倍負例的測試集

pos_prob_lr_dup = lr.predict_proba(X_test_dup)[:,1]
pos_prob_rf_dup = rf.predict_proba(X_test_dup)[:,1]
tpr_lr_dup,fpr_lr_dup,auc_lr_dup = get_roc(pos_prob_lr_dup,y_test_dup)
tpr_rf_dup,fpr_rf_dup,auc_rf_dup = get_roc(pos_prob_rf_dup,y_test_dup)

plt.figure(figsize=(10,6))
plt.plot(fpr_lr_dup,tpr_lr_dup,label="Logistic Regression (AUC: {:.3f})".format(auc_lr_dup),linewidth=2)
plt.plot(fpr_rf_dup,tpr_rf_dup,'g',label="Random Forest (AUC: {:.3f})".format(auc_rf_dup),linewidth=2)
plt.xlabel("False Positive Rate",fontsize=16)
plt.ylabel("True Positive Rate",fontsize=16)
plt.title("ROC Curve",fontsize=16)
plt.legend(loc="lower right",fontsize=16)

這裡寫圖片描述

Logistic Regression的曲線幾乎和先前一模一樣,但Random Forest的曲線卻產生了很大變化。箇中原因看一下兩個分類器的預測概率就明白了:

pos_prob_lr_dup[:20]
array([0.15813023, 0.12075471, 0.02763748, 0.00983065, 0.06201179,
       0.04986294, 0.09926128, 0.05632981, 0.15558692, 0.05856262,
       0.08661055, 0.00787402, 0.1617371 , 0.04063957, 0.14103442,
       0.07734239, 0.0213237 , 0.03968638, 0.03771455, 0.04874451])
pos_prob_rf_dup[:20]
array([0. , 0. , 0.1, 0.1, 0. , 0.1, 0.2, 0. , 0.1, 0.1, 0.1, 0. , 0. ,
       0.2, 0. , 0. , 0.2, 0. , 0.1, 0. ])

可以看到Logistic Regression的預測概率幾乎沒有重複,而Random Forest的預測概率則有很多重複,因為Logistic Regression可以天然輸出概率,而Random Forest本質上屬於樹模型,只能輸出離散值。scikit-learn中樹模型的predict_proba() 方法表示的是一個葉節點上某一類別的樣本比例,但只顯示小數點後一位,致使大量樣本的預測概率都一樣。當畫ROC曲線時需要先將樣本根據預測概率排序,若幾個樣本的概率一樣,則只能按原來的順序排列。上面的操作就是將所有累加的負例都排在了原始資料後面,致使正例的順序都很靠前,造成Random Forest的結果好了不少。解決辦法就是將所有樣本隨機排序,就能產生和原來差不多的ROC曲線了:

index = np.random.permutation(len(X_test_dup))
X_test_dup = X_test_dup[index]
y_test_dup = y_test_dup[index]

ROC曲線的缺點

  1. 上文提到ROC曲線的優點是不會隨著類別分佈的改變而改變,但這在某種程度上也是其缺點。因為負例N增加了很多,而曲線卻沒變,這等於產生了大量FP。像資訊檢索中如果主要關心正例的預測準確性的話,這就不可接受了。

  2. 在類別不平衡的背景下,負例的數目眾多致使FPR的增長不明顯,導致ROC曲線呈現一個過分樂觀的效果估計。ROC曲線的橫軸採用FPR,根據FPR = FPN = FPFP+TN,當負例N的數量遠超正例P時,FP的大幅增長只能換來FPR的微小改變。結果是雖然大量負例被錯判成正例,在ROC曲線上卻無法直觀地看出來。(當然也可以只分析ROC曲線左邊一小段)

    舉個例子,假設一個數據集有正例20,負例10000,開始時有20個負例被錯判,FPR=2020+9980=0.002,接著又有20個負例錯判,FPR2=4040+9960=0.004,在ROC曲線上這個變化是很細微的。而與此同時Precision則從原來的0.5下降到了0.33,在PR曲線上將會是一個大幅下降。

PR (Precision Recall) 曲線

PR曲線展示的是Precision vs Recall的曲線,PR曲線與ROC曲線的相同點是都採用了TPR (Recall),都可以用AUC來衡量分類器的效果。不同點是ROC曲線使用了FPR,而PR曲線使用了Precision,因此PR曲線的兩個指標都聚焦於正例。類別不平衡問題中由於主要關心正例,所以在此情況下PR曲線被廣泛認為優於ROC曲線。

PR曲線的繪製與ROC曲線類似,PR曲線的AUC面積計算公式為:

n(RnRn1)Pn

下面仍使用上面的資料集畫圖:

def get_pr(pos_prob,y_true):
    pos = y_true[y_true==1]
    threshold = np.sort(pos_prob)[::-1]
    y = y_true[pos_prob.argsort()[::-1]]
    recall = [] ; precision = []
    tp = 0 ; fp = 0
    auc = 0
    for i in range(len(threshold)):
        if y[i] == 1:
            tp += 1
            recall.append(tp/len(pos))
            precision.append(tp/(tp+fp))
            auc += (recall[i]-recall[i-1])*precision[i]
        else:
            fp += 1
            recall.append(tp/len(pos))
            precision.append(tp/(tp+fp))
    return precision,recall,auc

precision_lr,recall_lr,auc_lr = get_pr(pos_prob_lr,y_test)
precision_rf,recall_rf,auc_rf = get_pr(pos_prob_rf,y_test)

plt.figure(figsize=(10,6))
plt.plot(recall_lr,precision_lr,label="Logistic Regression (AUC: {:.3f})".format(auc_lr),linewidth=2)
plt.plot(recall_rf,precision_rf,label="Random Forest (AUC: {:.3f})".format(auc_rf),linewidth=2)
plt.xlabel("Recall",fontsize=16)
plt.ylabel("Precision",fontsize=16)
plt.title("Precision Recall Curve",fontsize=17)
plt.legend(fontsize=16)

這裡寫圖片描述

可以看到上文中ROC曲線下的AUC面積在0.8左右,而PR曲線下的AUC面積在0.68左右,類別不平衡問題中ROC曲線確實會作出一個比較樂觀的估計,而PR曲線則因為Precision的存在會不斷顯現FP的影響。

使用場景

  1. ROC曲線由於兼顧正例與負例,所以適用於評估分類器的整體效能,相比而言PR曲線完全聚焦於正例。
  2. 如果有多份資料且存在不同的類別分佈,比如信用卡欺詐問題中每個月正例和負例的比例可能都不相同,這時候如果只想單純地比較分類器的效能且剔除類別分佈改變的影響,則ROC曲線比較適合,因為類別分佈改變可能使得PR曲線發生變化時好時壞,這種時候難以進行模型比較;反之,如果想測試不同類別分佈下對分類器的效能的影響,則PR曲線比較適合。

  3. 如果想要評估在相同的類別分佈下正例的預測情況,則宜選PR曲線。

  4. 類別不平衡問題中,ROC曲線通常會給出一個樂觀的效果估計,所以大部分時候還是PR曲線更好。

  5. 最後可以根據具體的應用,在曲線上找到最優的點,得到相對應的precision,recall,f1 score等指標,去調整模型的閾值,從而得到一個符合具體應用的模型。

相關推薦

機器學習類別平衡問題 (2) —— ROCPR曲線

完整程式碼 ROC曲線和PR(Precision - Recall)曲線皆為類別不平衡問題中常用的評估方法,二者既有相同也有不同點。本篇文章先給出ROC曲線的概述、實現方法、優缺點,再闡述PR曲線的各項特點,最後給出兩種方法各自的使用場景。 R

機器學習類別平衡問題 (1) —— 各種評估指標

機器學習之類別不平衡問題 (1) —— 各種評估指標 機器學習之類別不平衡問題 (2) —— ROC和PR曲線 在二分類問題中,通常假設正負類別相對均衡,然而實際應用中類別不平衡的問題,如100, 1000, 10000倍的資料偏斜是非常常見的,比如疾病

機器學習樣本平衡

機器學習之樣本不平衡 1.樣本不平衡導致什麼問題? 在機器學習的分類問題中,以二分類為例,如果訓練集合的正例和負例的樣本不平衡,相差懸殊很大。比如針對這個不平衡的訓練結合運用邏輯迴歸的時候,一般來說,邏輯迴歸的閾值0~1,常取0.5,當樣本不平衡時,採用預設的分類閾值可能會導致輸出全

系統學習機器學習樣本平衡問題處理

原文連結:http://blog.csdn.net/heyongluoyao8/article/details/49408131 在分類中如何處理訓練集中不平衡問題   在很多機器學習任務中,訓練集中可能會存在某個或某些類別下的樣本數遠大於另一些類別下的樣本數目。即類別不平衡,為了使得學習達

機器學習類別平衡學習

本文主要記錄 《機器學習》一書中關於類別不平衡問題的處理。   類別不平衡問題(class-imbalance)就是說對於分類任務來說,不同類別的訓練樣例相差很大的情況。不是一般性,這裡主要介紹負樣本遠遠多於正樣本的情況。(在閱讀深度神經網路論文時,發現這種情

[轉]如何處理機器學習中的平衡類別

down 觀測 input 推薦 可能 type 兩個 好的 exchange 如何處理機器學習中的不平衡類別 原文地址:How to Handle Imbalanced Classes in Machine Learning 原文作者:elitedatascienc

機器學習中樣本平衡處理辦法

   在機器學習任務中,我們經常會遇到這種困擾:資料不平衡問題。比如在廣告點選預估、反欺詐、風控裡面。 資料不平衡問題主要存在於有監督機器學習任務中。當遇到不平衡資料時,以總體分類準確率為學習目標的傳統分類演算法會過多地關注多數類,從而使得少數類樣本的分類效能下降。絕大

2機器學習兄弟連:K近鄰K-means

關鍵詞:從K近鄰到最近鄰,監督學習,資料帶lable,效率優化(從線性搜尋到kd樹搜尋),缺點是需要儲存所有資料,空間複雜度大。可以利用kd數來優化k-means演算法。 學習了kNN和K-means演算法後,仔細分析比較了他們之間的異同以及應用場景總結成此文供讀者參

從重取樣到資料合成:如何處理機器學習中的平衡分類問題?

轉自:http://www.sohu.com/a/129333346_465975 選自Analytics Vidhya 作者:Upasana Mukherjee 機器之心編譯 參與:馬亞雄、微胖、黃小天、吳攀 如果你研究過一點機器學習和資料科學,你肯定遇到過不平衡的類分

機器學習」資料平衡情況下的處理方法(1)

1. background   前端時間想換工作,於是面了幾家公司。發現了公司面試基本會問當資料集分佈不平衡的時候該怎麼處理。在現實做專案的時候這種情況也會很多。於是做了一下整理。2. 資料不平衡    資料不平衡的情況主要出現在二分類。比如現在公司做的重要郵件檢測。幾千個郵

如何解決機器學習中資料平衡問題

這幾年來,機器學習和資料探勘非常火熱,它們逐漸為世界帶來實際價值。與此同時,越來越多的機器學習演算法從學術界走向工業界,而在這個過程中會有很多困難。資料不平衡問題雖然不是最難的,但絕對是最重要的問題之一。  一、資料不平衡 在學術研究與教學中,很多演算法都有一個基本假設,那

虛擬機器學習二:垃圾收集器記憶體分配策略

1.物件是否可回收 1.1引用計數演算法 引用計數演算法:給物件中新增一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時候計數器值為0的物件就是不可能再被使用的物件。 客觀來說,引用計數演算法的實現簡單,判定效率高,在大部分情況下都是

機器學習特徵值/特徵向量的解析應用

機器學習中,矩陣的特徵值/特徵向量理論有著非常廣泛的應用,比如資料降維 [1],人臉識別 [2]等。本文主要介紹特徵值/特徵向量。 1. 特徵值 定義: 給定n×nn\times nn×n階方陣AAA,如果存在數值λ\lambdaλ和nnn維非零向量x⃗\ve

java虛擬機器學習執行緒共享記憶體區執行緒私有區

 執行緒共享指的就是可以允許被所有執行緒共享訪問的一塊記憶體,包括堆區,方法區和執行時常量池。  1. java堆區      java堆區在虛擬機器啟動時被建立,並且他在實際記憶體中是可以不連續的。

機器學習區域性加權、嶺迴歸前向逐步迴歸

  都說萬事開頭難,可一旦開頭,就是全新的狀態,就有可能收穫自己未曾預料到的成果。記錄是為了更好的監督、理解和推進,學習過程中用到的資料集和程式碼都將上傳到github   迴歸是對一個或多個自變數和因變數之間的關係進行建模,求解的一種統計方法,之前的部落格中總結了線上性迴歸中使用最小二乘法推導最優引

機器學習-類別平衡問題

之前 size 訓練 最近鄰 機制 每次 問題 線性 大於 引言:我們假設有這種情況,訓練數據有反例998個,正例2個,模型是一個永遠將新樣本預測為反例的學習器,就能達到99.8%的精度,這樣顯然是不合理的。 類別不平衡:分類任務中不同類別的訓練樣例數差別很大。

機器學習:如何處理資料中的「類別平衡」?

轉自: 機器學習中常常會遇到資料的類別不平衡(class imbalance),也叫資料偏斜(class skew)。以常見的二分類問題為例,我們希望預測病人是否得了某種罕見疾病。但在歷史資料中,陽性的比例可能很低(如百分之0.1)。在這種情況下,學習出好的分類器是

機器學習中的類別平衡問題

 類別不平衡問題指分類任務中不同類別的訓練樣本數目差別很大的情況。 下面介紹幾種緩解類別不平衡的方法: 1、欠取樣 即去除多餘的樣本,使得正負樣本數目基本一致。 注意:(1)由於丟棄了一些樣本,訓練速度相對加快了。           &n

8種應對機器學習資料集類別平衡的策略

資料集類別不平衡通常發生在分類問題上,例如有兩個類別(A,B)的資料集,A有80個,而B有20個,那麼這個資料集是不平衡的。大多數資料集每一個類別通常不是完全的平衡,小的不平衡不會有太大的問題。但是當樣本分佈差距很大的時候,就會有很大的影響。嚴重的不平衡會導致訓練的模型大概率

機器學習路: python 樸素貝葉斯分類器 預測新聞類別

groups group news ckey put epo test electron final 使用python3 學習樸素貝葉斯分類api 設計到字符串提取特征向量 歡迎來到我的git下載源代碼: https://github.com/linyi0604/kag