1. ROC曲線的定義
ROC的全稱是Receiver Operating Characteristic Curve,中文名字叫“受試者工作特征曲線”,顧名思義,其主要的分析方法就是畫這條特征曲線。這里在網上找了一個比較好的圖樣示例如下,

該曲線的橫坐標為假陽性率(False Positive Rate, FPR),N是真實負樣本的個數,FP是N個負樣本中被分類器預測為正樣本的個數。
縱坐標為真陽性率(True Positive Rate, TPR),
P是真實正樣本的個數,TP是P個正樣本中被分類器預測為正樣本的個數。
舉一個簡單的例子方便大家的理解,還是剛才雷達的例子。假設現在有10個雷達信號警報,其中8個是真的轟炸機(P)來了,2個是大鳥(N)飛過,經過某分析員解析雷達的信號,判斷出9個信號是轟炸機,剩下1個是大鳥,其中被判定為轟炸機的信號中,有1個其實是大鳥的信號(FP=1),而剩下8個確實是轟炸機信號(TP=8)。因此可以計算出FPR為,TPR為
,而
就對應ROC曲線上一點。
說到這里,想必大家已經明白這倆個指標的計算方法,再往深挖一點,可以思考一下這倆個指標背后的原理。還是雷達的例子,敏銳的雷達系統我們肯定希望它能把所有的敵方轟炸機來襲都感知到並預測出來,即TPR越高越好,但我們又不希望它把大鳥的飛過也當成轟炸機來預警,即FRP越低越好。因此,大家可以發現,這倆個坐標值其實是有相互制約的一個概念在里面。
當繪制完成曲線后,就會對模型有一個定性的分析,如果要對模型進行量化的分析,此時需要引入一個新的概念,就是AUC(Area under roc Curve)面積,這個概念其實很簡單,就是指ROC曲線下的面積大小,而計算AUC值只需要沿着ROC橫軸做積分就可以了。真實場景中ROC曲線一般都會在這條直線的上方,所以AUC的取值一般在0.5~1之間。AUC的值越大,說明該模型的性能越好。
2. ROC曲線的繪制原理
如果大家對二值分類模型熟悉的話,都會知道其輸出一般都是預測樣本為正例的概率,而事實上,ROC曲線正是通過不斷移動分類器的“閾值”來生成曲線上的一組關鍵點的。可能這樣講有點抽象,還是舉剛才雷達兵的例子。每一個雷達兵用的都是同一台雷達返回的結果,但是每一個雷達兵內心對其屬於敵軍轟炸機的判斷是不一樣的,可能1號兵解析后認為結果大於0.9,就是轟炸機,2號兵解析后認為結果大於0.85,就是轟炸機,依次類推,每一個雷達兵內心都有自己的一個判斷標准(也即對應分類器的不同“閾值”),這樣針對每一個雷達兵,都能計算出一個ROC曲線上的關鍵點(一組FPR,TPR值),把大家的點連起來,也就是最早的ROC曲線了。
為方便大家進一步理解,本菇也在網上找到了一個示例跟大家一起分享【4】。下圖是一個二分模型真實的輸出結果,一共有20個樣本,輸出的概率就是模型判定其為正例的概率,第二列是樣本的真實標簽。

現在我們指定一個閾值為0.9,那么只有第一個樣本(0.9)會被歸類為正例,而其他所有樣本都會被歸為負例,因此,對於0.9這個閾值,我們可以計算出FPR為0,TPR為0.1(因為總共10個正樣本,預測正確的個數為1),那么我們就知道曲線上必有一個點為(0, 0.1)。依次選擇不同的閾值(或稱為“截斷點”),畫出全部的關鍵點以后,再連接關鍵點即可最終得到ROC曲線如下圖所示。

其實還有一種更直觀的繪制ROC曲線的方法,這邊簡單提一下。就是把橫軸的刻度間隔設為,縱軸的刻度間隔設為
,N,P分別為負樣本與正樣本數量。然后再根據模型的輸出結果降序排列,依次遍歷樣本,從0開始繪制ROC曲線,每遇到一個正樣本就沿縱軸方向繪制一個刻度間隔的曲線,每遇到一個負樣本就沿橫軸方向繪制一個刻度間隔的曲線,遍歷完所有樣本點以后,曲線也就繪制完成了。究其根本,其最大的好處便是不需要再去指定閾值尋求關鍵點了,每一個樣本的輸出概率都算是一個閾值了。當然,無論是工業界還是學術界的實現,都不可能手動去繪制,下面就來講一下如何用Python高效繪制ROC曲線。
3. ROC曲線繪制的Python實現
熟悉sklearn的讀者肯定都知道,幾乎所有評估模型的指標都來自sklearn庫下面的metrics,包括計算召回率,精確率等。ROC曲線的繪制也不例外,都得先計算出評估的指標,也就是從metrics里面去調用roc_curve, auc,然后再去繪制。
from sklearn.metrics import roc_curve, auc
roc_curve和auc的官方說明教程示例如下
# 數據准備 >>> import numpy as np >>> from sklearn import metrics >>> y = np.array([1, 1, 2, 2]) >>> scores = np.array([0.1, 0.4, 0.35, 0.8]) # roc_curve的輸入為 # y: 樣本標簽 # scores: 模型對樣本屬於正例的概率輸出 # pos_label: 標記為正例的標簽,本例中標記為2的即為正例 >>> fpr, tpr, thresholds = metrics.roc_curve(y, scores, pos_label=2) # 假陽性率 >>> fpr array([ 0. , 0.5, 0.5, 1. ]) # 真陽性率 >>> tpr array([ 0.5, 0.5, 1. , 1. ]) # 閾值 >>> thresholds array([ 0.8 , 0.4 , 0.35, 0.1 ]) # auc的輸入為很簡單,就是fpr, tpr值 >>> auc = metrics.auc(fpr, tpr) >>> auc 0.75
因此調用完roc_curve以后,我們就齊全了繪制ROC曲線的數據。接下來的事情就很簡單了,調用plt即可,還是用官方的代碼示例一步到底。
import matplotlib.pyplot as plt plt.figure() lw = 2 plt.plot(fpr, tpr, color='darkorange', lw=lw, label='ROC curve (area = %0.2f)' % auc) plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--') plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate') plt.title('Receiver operating characteristic example') plt.legend(loc="lower right") plt.show()
最終生成的ROC曲線結果如下圖。