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()
同樣,這裡也有一個折中,更高的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()
如上圖所示,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。