本文用于理解ROC曲線的定義,繪制過程及其應(yīng)用實現(xiàn),主要用于自我溫習回顧基礎(chǔ)
基本目錄如下:
什么是ROC曲線?
1.1 ROC曲線的歷史
1.2 ROC曲線的定義
1.3 ROC曲線的應(yīng)用場景如何繪制ROC曲線?
2.1 ROC曲線的繪制原理
2.2 ROC曲線繪制的Python實現(xiàn)
------------------第一菇 - 什么是ROC曲線------------------
1.1 ROC曲線的歷史
自從讀了吳軍老師的《數(shù)學之美》,我就想明白了一件事情,如果想要講明白一件事情,一定要把他的歷史淵源都講明白,這樣我們才能對其理解透徹,而不是單純學到會用就好~試想,有多少人在讀這篇文章之前,會想到ROC曲線在軍事上的運用呢?接下來,我就當一回搬運工,把ROC曲線的誕生淵源都捋一捋~
經(jīng)過一番網(wǎng)上調(diào)查,ROC曲線起源于第二次世界大戰(zhàn)時期雷達兵對雷達的信號判斷【1】。當時每一個雷達兵的任務(wù)就是去解析雷達的信號,但是當時的雷達技術(shù)還沒有那么先進,存在很多噪聲(比如一只大鳥飛過),所以每當有信號出現(xiàn)在雷達屏幕上,雷達兵就需要對其進行破譯。有的雷達兵比較謹慎,凡是有信號過來,他都會傾向于解析成是敵軍轟炸機,有的雷達兵又比較神經(jīng)大條,會傾向于解析成是飛鳥。這個時候,雷達兵的上司就很頭大了,他急需一套評估指標來幫助他匯總每一個雷達兵的預(yù)測信息,以及來評估這臺雷達的可靠性(如果不論哪一類雷達兵都能準確預(yù)測,那這臺雷達就很NB~讀者可思考其緣由)。于是,最早的ROC曲線分析方法就誕生了,用來作為評估雷達可靠性的指標~在那之后,ROC曲線就被廣泛運用于醫(yī)學以及機器學習領(lǐng)域~
1.2 ROC曲線的定義
ROC的全稱是Receiver Operating Characteristic Curve,中文名字叫“受試者工作特征曲線”,顧名思義,其主要的分析方法就是畫這條特征曲線。這里在網(wǎng)上找了一個比較好的圖樣示例如下,

該曲線的橫坐標為假陽性率(False Positive Rate, FPR),N是真實負樣本的個數(shù),
FP是N個負樣本中被分類器預(yù)測為正樣本的個數(shù)。
縱坐標為真陽性率(True Positive Rate, TPR),
P是真實正樣本的個數(shù),
TP是P個正樣本中被分類器預(yù)測為正樣本的個數(shù)。
舉一個簡單的例子方便大家的理解,還是剛才雷達的例子。假設(shè)現(xiàn)在有10個雷達信號警報,其中8個是真的轟炸機(P)來了,2個是大鳥(N)飛過,經(jīng)過某分析員解析雷達的信號,判斷出9個信號是轟炸機,剩下1個是大鳥,其中被判定為轟炸機的信號中,有1個其實是大鳥的信號(FP=1),而剩下8個確實是轟炸機信號(TP=8)。因此可以計算出FPR為,TPR為
,而
就對應(yīng)ROC曲線上一點。
說到這里,想必大家已經(jīng)明白這倆個指標的計算方法,再往深挖一點,可以思考一下這倆個指標背后的原理。還是雷達的例子,敏銳的雷達系統(tǒng)我們肯定希望它能把所有的敵方轟炸機來襲都感知到并預(yù)測出來,即TPR越高越好,但我們又不希望它把大鳥的飛過也當成轟炸機來預(yù)警,即FRP越低越好。因此,大家可以發(fā)現(xiàn),這倆個坐標值其實是有相互制約的一個概念在里面。
當繪制完成曲線后,就會對模型有一個定性的分析,如果要對模型進行量化的分析,此時需要引入一個新的概念,就是AUC(Area under roc Curve)面積,這個概念其實很簡單,就是指ROC曲線下的面積大小,而計算AUC值只需要沿著ROC橫軸做積分就可以了。真實場景中ROC曲線一般都會在這條直線的上方,所以AUC的取值一般在0.5~1之間。AUC的值越大,說明該模型的性能越好。
1.3 ROC曲線的應(yīng)用場景
ROC曲線的應(yīng)用場景有很多,根據(jù)上述的定義,其最直觀的應(yīng)用就是能反映模型在選取不同閾值的時候其敏感性(sensitivity, FPR)和其精確性(specificity, TPR)的趨勢走向【2】。不過,相比于其他的P-R曲線(精確度和召回率),ROC曲線有一個巨大的優(yōu)勢就是,當正負樣本的分布發(fā)生變化時,其形狀能夠基本保持不變,而P-R曲線的形狀一般會發(fā)生劇烈的變化,因此該評估指標能降低不同測試集帶來的干擾,更加客觀的衡量模型本身的性能。要解釋清楚這個問題的話,大家還是先回顧一下混淆矩陣。

其中,精確率P的計算公式為,
召回率R的計算公式為,
此時,若將負樣本的數(shù)量增加,擴大個10倍,可以預(yù)見FP,TN都會增加,必然會影響到P,R。但ROC曲線的倆個值,F(xiàn)PR只考慮第二行,N若增大10倍,則FP,TN也會成比例增加,并不影響其值,TPR更是只考慮第一行,不會受到影響。這里在網(wǎng)上盜個圖【3】,方便大家理解哈~

其中第一行ab均為原數(shù)據(jù)的圖,左邊為ROC曲線,右邊為P-R曲線。第二行cd為負樣本增大10倍后倆個曲線的圖。可以看出,ROC曲線基本沒有變化,但P-R曲線確劇烈震蕩。因此,在面對正負樣本數(shù)量不均衡的場景下,ROC曲線(AUC的值)會是一個更加穩(wěn)定能反映模型好壞的指標。
------------------第二菇 - 如何繪制ROC曲線------------------
2.1 ROC曲線的繪制原理
如果大家對二值分類模型熟悉的話,都會知道其輸出一般都是預(yù)測樣本為正例的概率,而事實上,ROC曲線正是通過不斷移動分類器的“閾值”來生成曲線上的一組關(guān)鍵點的。可能這樣講有點抽象,還是舉剛才雷達兵的例子。每一個雷達兵用的都是同一臺雷達返回的結(jié)果,但是每一個雷達兵內(nèi)心對其屬于敵軍轟炸機的判斷是不一樣的,可能1號兵解析后認為結(jié)果大于0.9,就是轟炸機,2號兵解析后認為結(jié)果大于0.85,就是轟炸機,依次類推,每一個雷達兵內(nèi)心都有自己的一個判斷標準(也即對應(yīng)分類器的不同“閾值”),這樣針對每一個雷達兵,都能計算出一個ROC曲線上的關(guān)鍵點(一組FPR,TPR值),把大家的點連起來,也就是最早的ROC曲線了。
為方便大家進一步理解,本菇也在網(wǎng)上找到了一個示例跟大家一起分享【4】。下圖是一個二分模型真實的輸出結(jié)果,一共有20個樣本,輸出的概率就是模型判定其為正例的概率,第二列是樣本的真實標簽。

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

其實還有一種更直觀的繪制ROC曲線的方法,這邊簡單提一下。就是把橫軸的刻度間隔設(shè)為,縱軸的刻度間隔設(shè)為
,N,P分別為負樣本與正樣本數(shù)量。然后再根據(jù)模型的輸出結(jié)果降序排列,依次遍歷樣本,從0開始繪制ROC曲線,每遇到一個正樣本就沿縱軸方向繪制一個刻度間隔的曲線,每遇到一個負樣本就沿橫軸方向繪制一個刻度間隔的曲線,遍歷完所有樣本點以后,曲線也就繪制完成了。究其根本,其最大的好處便是不需要再去指定閾值尋求關(guān)鍵點了,每一個樣本的輸出概率都算是一個閾值了。當然,無論是工業(yè)界還是學術(shù)界的實現(xiàn),都不可能手動去繪制,下面就來講一下如何用Python高效繪制ROC曲線。
2.2 ROC曲線繪制的Python實現(xiàn)
熟悉sklearn的讀者肯定都知道,幾乎所有評估模型的指標都來自sklearn庫下面的metrics,包括計算召回率,精確率等。ROC曲線的繪制也不例外,都得先計算出評估的指標,也就是從metrics里面去調(diào)用roc_curve, auc,然后再去繪制。
from sklearn.metrics import roc_curve, auc
roc_curve和auc的官方說明教程示例如下【5】。
# 數(shù)據(jù)準備
>>> 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
因此調(diào)用完roc_curve以后,我們就齊全了繪制ROC曲線的數(shù)據(jù)。接下來的事情就很簡單了,調(diào)用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曲線結(jié)果如下圖。

至此,整一套ROC曲線的繪制就說明白了。
簡單總結(jié)一下本文,先是講述了ROC曲線的歷史淵源,引導(dǎo)讀者理解ROC曲線的各個基本概念,又與P-R曲線做了詳細的對比,讓讀者理解其應(yīng)用場景,最后接地氣的輕微解讀了一番其繪制過程,并附上了代碼實現(xiàn)。希望大家讀完本文后對ROC曲線會有一個全新的認識。有說的不對的地方也請大家指出,多多交流,大家一起進步~??
參考文獻:
【1】https://www.ncbi.nlm.nih.gov/books/NBK22319/
【2】https://stats.stackexchange.com/questions/28745/advantages-of-roc-curves
【3】https://blog.csdn.net/songyunli1111/article/details/82285266
【4】https://www.zhihu.com/question/22844912/answer/246037337
【5】http://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_curve.html#sklearn.metrics.roc_curve