天天看點

分類問題(三)ROC曲線

ROC曲線

ROC曲線是二進制分類器中常用的工具,它的全稱是 Receiver Operating Characteristic,接收者操作特征曲線。它與precision/recall 曲線特别相似,但是它畫出的是true positive rate(recall的另一種叫法)對應false positive rate (FPR)的圖。FPR是“負執行個體”(negative instances) 被錯誤地分類成“正執行個體”(positive)的比率。它等同于 1 減去true negative rate(TNR,“負執行個體”被正确地分類成“負執行個體”的比率)。TNR也被稱為特異性(specificity)。是以ROC曲線畫出的也是 sensitivity(也就是recall)vs (1 – specificity)。

為了畫出ROC 曲線,我們首先需要計算在不同門檻值下的TPR與FPR值,使用roc_curve() 方法:

from sklearn.metrics import roc_curve

fpr, tpr, thresholds = roc_curve(y_train_5, y_scores)      

然後使用matplotlib 畫出FPR對應TPR的圖:

def plot_roc_curve(fpr, tpr, label=None):
    plt.plot(fpr, tpr, linewidth=2, label=label)
    plt.plot([0, 1], [0, 1], 'k--') #加上虛線對角線

plot_roc_curve(fpr, tpr)
plt.show()      
分類問題(三)ROC曲線

同樣,這裡也有一個折中,更高的recall(TPR)也就意味着分類器會産生更多的false positives(FPR)。虛線代表的是一個完全随機的分類器的ROC曲線,一個好的分類器的ROC曲線要盡可能地遠離這條虛線,并要盡可能地接近左上角。

一種比較分類器的辦法是評估AUC(area under the curve,曲線下方面積),一個完美的分類器的ROC AUC應等于1,而一個完全随機的分類器的ROC AUC則為0.5。sk-learn提供了一個方法用于計算ROC AUC:

from sklearn.metrics import roc_auc_score

roc_auc_score(y_train_5, y_scores)
>0.9604938554008616      

由于ROC曲線與precision/recall(或者PR)曲線非常相似,是以大家可能會好奇到底使用哪個。根據經驗,任何時候當positive 類别很少、或是在關注false positive甚于false negative時,使用PR曲線。反之則使用ROC曲線。例如,我們看一下上一個ROC曲線(以及ROC AUC分數),我們可能認為分類器非常好。但是這主要是因為資料集中positive instances(也就是數字5)較少,相對于“非5”少很多。相反,從PR曲線來看,我們可以看到其實這個分類器還有提升的空間(PR曲線應該盡可能地靠近右上角)。

我們接下來訓練一個RandomForestClassifier,并對比它的ROC 曲線以及ROC AUC分數。首先,我們需要得到訓練集中每條資料的分數。但是RandomForestClassifier類并沒有提供decision_function() 的方法,它提供的是一個predict_proba() 方法。一般sk-learn中的分類器中,基本都是提供的這兩個方法中的其一。predict_proba() 方法傳回一個數組,裡面每行是一條資料,每列是一個類别,裡面的數值就是這條資料屬于這個類别的機率(例如,某條資料有70%的機率代表數字5)。

from sklearn.ensemble import RandomForestClassifier

forest_clf = RandomForestClassifier(random_state=42)
y_probas_forest = cross_val_predict(forest_clf, X_train, y_train_5, cv=3, method='predict_proba')
y_probas_forest
>array([[0.1, 0.9],

       [1. , 0. ],

       [0.9, 0.1],

       ...,

       [0. , 1. ],

       [1. , 0. ],

       [1. , 0. ]])      

但是為了畫出ROC曲線,我們需要的是分數(scores),并不是機率。一個簡單的辦法是使用positive類的機率作為分數:

y_scores_forest = y_probas_forest[:, 1]
fpr_forest, tpr_forest, thresholds_forest = roc_curve(y_train_5, y_scores_forest)      

現在我們已經有了分數,可以畫出ROC曲線(最好是也畫出第一個分類器的ROC曲線作為對比):

plt.plot(fpr, tpr, 'b:', label='SGD')
plot_roc_curve(fpr_forest, tpr_forest, 'Random Forest')
plt.legend(loc='lower right')
plt.show()      
分類問題(三)ROC曲線

如上圖所示,RandomForestClassifier的ROC曲線看起來比SGDClassifier的更好:它更接近于左上角。顯而易見,它的ROC AUC分數也會更高:

roc_auc_score(y_train_5, y_scores_forest)
>0.9920527492698306      

如果進一步計算它的precision與recall的話,可以分别得到98% 的precision,以及82%的recall:

y_train_forest_pred = cross_val_predict(forest_clf, X_train, y_train_5, cv=3)
precision_score(y_train_5, y_train_forest_pred)
>0.986046511627907

recall_score(y_train_5, y_train_forest_pred)
>0.8212506917542889      

相較上一個分類器,有了很大的提升。

至此,希望大家已經了解了:

  • 如何訓練一個二進制分類器
  • 為任務選擇合适的名額
  • 使用交叉驗證評估分類器
  • 使用precision/recall tradeoff 滿足你的需求
  • 通過ROC曲線以及ROC AUC分數比較不同的模型

在二進制分類器完成之後,我們之後接下來繼續看一下多類别分類,讓分類器不僅僅是隻區分數字5。