在前一篇數值預估評估方法,已介紹我們進行數值預測時,怎麼評估模型的好壞,在這篇,我們來介紹機率預測模型的評估方法。
前情提要
模型評估-驗證指標(validation index)
若將預測這件事簡單區分成兩大種類,大致可分為
1. 機率預測,比如會不會下雨、下一張牌的紅心A…
2. 數值預測,比如預測下一季的銷售量、捷運站的客流量…
我們利用所蒐集到的資料訓練出模型進行預測,然而怎麼評估模型成效(Performance)呢?
我們會使用驗證指標(validation index)來當作成效參考,對應到機器學習領域,依據應用分為「分類指標」和「回歸指標」。
機率預測的「分類指標」:
- 二元相關:混淆矩陣confusion matrix和相對應驗證指標、ROC曲線、AUC。
- 多元相關:多元混淆矩陣和相對應驗證指標。
數值預測的「回歸指標」:
- 絕對誤差(Absolute Error, E)、相對誤差(Relative Error, e)
- 平均絕對誤差(Mean Absolute Error, MAE)
- 平均均方誤差(Mean Squared Error, MSE)
- 平均均方對數誤差(Mean Squared Logarithmic Error, MSLE)
- 正歸化均方誤差、均方根誤差
二元機率預測
本篇先從簡單的二元預測開始,甚麼是二元預測呢?舉例來說就是答案非正即負,例如:發生或不發生;正面或反面;A類或B類;下雨或不下雨,兩種情況的預測。記得以前研究所時,我們的專題是將山坡地切割成數公尺方形網格,利用機率預測判斷這個網格是否有可能山崩,這也是一種二元的機率預測。
複習一下統計學,機率是指事情出現的可能性,是對分類問題中某種類別出現的機率的描述。
混淆矩陣
混淆矩陣是最廣泛且最基本用來評估分類模型的方式,這邊舉例講解會較清楚。
假設有間醫院有500個疑似流感患者的病人做篩檢,其中實際有得到流感的人數是150人,未得到的是350人,然而醫院使用快篩法解省時間成本,但快篩法的結果是得到流感的有155人,未得到的有345人,其中包含有得到卻錯誤被篩為未得病的偽陰性15人,還有明明沒有流感卻被誤判為陽性的20人。這種文字敘述是不是讓人覺得很冗長也難理解呢?若我們做成誤差矩陣就一目了然!
對角線黃色區塊,代表快篩結果判斷正確的人數,另一邊未填色的則是快篩判斷錯誤的人數。
從圖上我們可以計算各種佔比變且轉化成機率表示,例如有得病卻篩檢錯誤的機率15/150=10%…
接下來我們就來介紹各種誤差矩陣算出來的各種數值!
我們從左上角順時鐘介紹:
當一個正類的資料點被預測為正值,即為真正類( True positive, TP),如圖左上;
當一個負類的資料點被預測為正值,即為偽正類(False positive, FP),如圖右上;
當一個負類的資料點被預測為負值,即為真負類( True negative, TN),如圖右下;
當一個正類的資料點被預測為負值,即為偽負類(False negative, FN),如圖左下。
直覺上,TP與TN可能是大眾直覺關注的地方。因為如果模型有很高的TP和TN值,就表示模型預測的正確性很高。
但對於我們在訓練模型時,更在意FP和FN,因為專注於改善錯誤,更有助於調整模型。
FN為一型錯誤:假警報(ɑ錯誤)
FP則為二型錯誤:錯過真相(β錯誤)。
一型錯誤指的是被發現的目標壓根不是需要被關注的對象;二型錯誤則相反,感興趣的目標未被發現。
透過混淆矩陣,我們很方便計算以下評估指標:
這些指標在統計學與機器學習有不同的慣用翻譯,以下介紹採用ML領域常見的用法,並盡我所知的補充。
總體比率:
總體準確率(Accuracy, Acc)
模型總體的準確率,有被正確預測的數量佔總體的比值,這個比值當然希望越高越好!
\[Acc=\frac{TP+TN}{TP+TN+FP+FN}\] 利用上述流感的例子,\(TA=(135+330)/500=0.93\)
總體錯誤率(Total Error Rate, TER)
指模型總體預測錯誤的比率,與總體準確率Accrucy和為1。 \[TER=\frac{FP+FN}{Total}=1-Acc\] 流感例子為\(TER=(20+15)/500=0.07\)
佔預測分類的邊際機率:
以預測為正或預測為負總數當作分母
精準度(Percision)
又稱為正元符合率,陽性預測值Positive predictive value(PPV),指模型中正確預測正樣本的數量佔預測為正數量的比值,是經常被用到的指標。 \[Percision=\frac{TP}{TP+FP}\] 流感例子的\(P=135/155=0.87\)
負元精準度;陰性預測值(Negative predictive value, NPV)
又稱為負元符合率,指模型中正確預測負樣本的數量佔預測為負數量的比值。 \[NPV=\frac{TN}{TN+FN}\] 流感例子的\(P=135/155=0.87\)
錯誤率(False Discovery Rate, FDR)
指模型錯誤地預測正樣本(稱為:型一錯誤)偽陽性的數量佔預測為正樣本的數量比值。對比於精準度(Percision) \[FDR=\frac{FP}{TP+FP}\] 流感例子為\(FDR=20/155=0.13\)
負元錯誤率(False Omission Rate, FOR)
指模型錯誤地預測負樣本(稱為:型一錯誤)偽陰性的數量佔預測為負樣本的數量比值。 \[FDR=\frac{FN}{TN+FN}\] 流感例子為\(FOR=135/150=0.9\)
佔實際分類的邊際機率:
以實際為正或實際為負總數當作分母
召回率(Recall)
又稱為真正率(True Positive Rate, TPR)、覆蓋率(Coverage Rate, CR)、靈敏度(Sensitivity)、查全率、擊中率或命中率。
它表示模型中被正確預測為正的樣本佔全體正樣本的比值,對於一些重要的事件預測,比如說疾病,這些關注的事件能不能有效被模型分類很重要。 \[Recall=\frac{TP}{TP+FN}\] 流感例子的\(Recall=135/150=0.9\) 若把流感改為最近影響世界的武漢肺炎,十個染病帶源者接受篩選,會有一個被誤判為陰性,雖然召回率高達九成,但那一成偽陰性誤判結果對防疫仍是很難接受的。
特異性(Specficity)
又稱為真負率(True Negative Rate, TNR)、負元覆蓋率(Negative Coverage Rate, NCR)、負元召回率、負元查全性。
它表示模型中被正確預測為負樣本佔全體負樣本的比值。 \[Specficity=\frac{TN}{FP+TN}\] 流感例子的\(Specficity=330/350=0.94\)
假正率 FPR
又稱為錯正率、虛報率、誤報率,是指模型錯誤地預測正樣本的數量佔實際負樣本的比值,對於模型而言,將預測為正的門檻下拉,導致整體預測為整的比例變多,可能能降低FN,卻回同時推升FP,這之間的平衡取捨則看模型的目的。 \[FPR=\frac{TN}{FP+TN}\] 流感例子的\(FPR=20/(20+330)=0.06\)
假負率 FNR
又稱為錯負率、漏報率,是指模型錯誤地預測負樣本的數量佔實際正樣本的比值,跟召回率也互相對應。 \[FNR=\frac{TN}{FP+TN}\] 流感例子的\(FNR=15/(15+135)=0.1\)
這裡引用網路上 Tommy大神整理的指標計算表
非常強大!
從這張圖可以很容易計算邊際機率,並能了解各參數彼此消長的情況。
缺點: 實務上很難單單從一個指標就判定這個模型的好壞,舉例來說,如果我們的模型是要預測廠房跳電的發生,可能一兩年才會發生一次,樣本非常少,這時候模型只要把99%的日子都歸納為陰性,一樣可以得到很高的精準度,但是真正斷電的時候模型也完全無法察覺!這個準確率99%的模型就不是我們想要的。在正負樣本數量不行衡的情況下,單看準確率就有很大的缺陷。
另外,製表前我們必須設定分類的門檻值,一般先設定為0.5,但實際上哪個值門檻最佳無法單從誤差矩陣直觀選取。
#install.packages('ROCR')
#require(ROCR)
#用ROCR套件中的範例資料集
data("ROCR.simple")
df <- data.frame(ROCR.simple)
df$predclass <- ifelse(df$predictions>0.5, 1, 0) #用0.5當作門檻值
print(cf <- table(df[,c("predclass","labels")]))## labels
## predclass 0 1
## 0 91 14
## 1 16 79
tp <- cf[2, 2]
tn <- cf[1, 1]
fp <- cf[2, 1]
fn <- cf[1, 2]
accuracy <- (tp + tn)/(tp + tn + fp + fn); accuracy## [1] 0.85
sensitivity <- tp/(tp + fn); sensitivity## [1] 0.8494624
specificity <- tn/(tn + fp); specificity## [1] 0.8504673
#install.packages('caret')
#require(caret)
confusionMatrix(cf, positive = "1")## Confusion Matrix and Statistics
##
## labels
## predclass 0 1
## 0 91 14
## 1 16 79
##
## Accuracy : 0.85
## 95% CI : (0.7928, 0.8965)
## No Information Rate : 0.535
## P-Value [Acc > NIR] : <2e-16
##
## Kappa : 0.6989
##
## Mcnemar's Test P-Value : 0.8551
##
## Sensitivity : 0.8495
## Specificity : 0.8505
## Pos Pred Value : 0.8316
## Neg Pred Value : 0.8667
## Prevalence : 0.4650
## Detection Rate : 0.3950
## Detection Prevalence : 0.4750
## Balanced Accuracy : 0.8500
##
## 'Positive' Class : 1
##
以上是直接觀察計算就可以得到的一級指標,透過上述的值,我們還可以進一步推算二級、三級指標。
F值
又稱為F-Measure或F-Score,它是精準度Precision \(P=\frac{TP}{TP+FP}\)和召回率Recall \(R=\frac{TP}{TP+FN}\)的加權調合平均值。
調合平均值?嘿!沒錯,就是我們以前算總電阻的時候會用倒數相加的那個。 對模型而言,當然希望精準度與召回率都越高越好,但是兩者卻彼此消長,提高P的同時可能導致R降低,這就是魚與熊掌的難題。
故要調較模型時便須有所取捨,這時候該怎麼抉擇呢?通常這當中有一個平衡點,這裡F值就派上用場了! \[F_{\alpha}=\frac{1}{\frac{\alpha}{P}+\frac{1-\alpha}{R}}=\frac{P\cdot R}{\alpha \cdot R+(1-\alpha) \cdot P}\] 另外,
\[\frac{1}{F_{\beta}}=\frac{1}{(\beta^{2}+1)} \times (\frac{1}{P} +\frac{\beta^{2}}{R})\] \[F_{\beta}=\frac{(\beta^{2}+1)\cdot P\cdot R}{\beta^{2} \cdot P+R}\] 若想知道公式推導,可以參考 Stackexchange
當\(\alpha=0.5\)或\(\beta=1\)時,就成為常見的F1-Measure了,這裡的1就是指β。 \[F_{1}=\frac{2 \cdot P \cdot R}{P+R}\] \[F_{1} \in [0,1]\] 而\(\alpha,\beta\)值代表甚麼呢?這兩值的大小表示召回率對精準度的相對重要程度。
當β=1時,稱為F1-score,這時,精準度和召回率都很重要,權重相同。但有些情況下,我們認為精準度更重要一點,那就調整β的值小於1,當我們認為召回率比較重要,那就調整β的值大於1。 Wiki
β=1,召回率的權重=精準度的權重,得到F1;
β>1,召回率的權重>精準度的權重;
β<1,召回率的權重<精準度的權重。
常用的還有\(F_{0.5}\)、\(F_{2}\)。
當\(F_{1}\)接近1時表示模型好,反正靠近0時則不好,一般來說我們只要比較兩個模型的F1值就可以分辨模型良莠。
但麻煩的問題又來了,如果你有兩個模型A與B:
A的精準度為90%,召回率為80%
B的精準度為80%,召回率為90%
兩個模型會有相同的F1值。
多元誤差矩陣
上面介紹了二元誤差矩陣,然而如果是分類問題,結果可能有多種(m種)分類,例如動物依特徵被分類成貓、狗、兔子…,這種情況多元矩陣仍然適用。總共的分類結果有M*M種,其中正確被分類的有M種,錯誤的會有M^2-M種。 這時候指標應該如何計算呢?有兩種方法:
Marco
第一種辦法是把m種分類拆成兩兩一組,每組都變成二元分類,我們把各個二元分類的混淆矩陣計算出來之後,再用各組的結果計算平均值。 \[Precision_{marco}=\frac{1}{n}\sum_{i=1}^{n}Precision_{i}\] \[Recall_{marco}=\frac{1}{n}\sum_{i=1}^{n}Recall_{i}\] \[{F_{1}}_{marco}=\frac{2}{\frac{1}{Precision_{marco}}+\frac{1}{Recall_{marco}}}\]
Micro
第二種辦法是,我們也可以將二元矩陣的對應元速進行平均,先得到TP,TN,FP,FN的平均值,再根據這些值來計算。 \[Precision_{mirco}=\frac{\bar{TP}}{\bar{TP}+\bar{FP}}\] \[Recall_{mirco}=\frac{\bar{TP}}{\bar{TP}+\bar{FN}}\] \[{F_{1}}_{mirco}=\frac{2}{\frac{1}{Precision_{mirco}}+\frac{1}{Recall_{mirco}}}\]
實際使用時,太多指標使用起來也不免感到零散,且必須根據問題類型有針對性的選擇使用,略麻煩。因此,我們也經常用圖表來協助判斷。
以下要介紹的圖表有ROC曲線、KS曲線、累計收益圖、累計提升圖、累計回應圖。
ROC曲線
ROC全名,Receiver Operating Characteristic,不需要記中文名字!沒人記得住的XDD。 以下引用以斯帖統計顧問的描述如下:
ROC曲線是以圖像的方式呈現二分類系統(binary classifier system)在特定的分類或閾值(discrimination threshold)下的表現。圖形的縱軸(y-axis)為真陽性率(true positive rate; TPR),又稱為敏感度(sensitivity);橫軸(x-axis)為偽陽性率(false-posiitive rate; FPR),以1 – 特異度(specificity)表示,而敏感度為將結果正確判斷為陽性的機率,特異度係將結果正確判斷為負向或陰性的機率。 當指定一個分界點(cut-point)來區分檢驗的陽性與陰性時,這個分界點會影響到診斷工具的敏感度(sensitivity)及特異度(specificity)。
這個分界點其實就是門檻值,舉例來說,如果今天模型預測降雨機率是68%,那麼該歸類為“雨天”陽性,還是“晴天”陰性呢?就看歸類為陽性的門檻值設定為多少,可想而知,當門檻值設定高時,FP會下降,但是FN會上升,而調低門檻值的話則相反。
那麼如何繪製ROC曲線呢?ROC曲線是由一系列 (FPR, TPR)點構成的,但一個特定的模型,只會有一個分類結果,即只有一組 (FPR, TPR),對應ROC曲線上的一個點,那一條線是怎麼連出來的呢?
因門檻值可以調整,隨著調高或調低門檻值,我們可以改變模型將預測機率歸類為正或負類的比例,進而得到不同的分類結果。 \(TPR=\frac{TP}{TP+FN}\);\(FPR=\frac{FP}{FP+TN}\),可一邊參照上圖了解門檻值改變對TPR,FPR的影響
圖片來自維基百科
模型對所有樣本分別計算出預測為陽性的機率,我們把這些值算出來後從小至大排列,依次將其當作門檻值,以此可以計算該閾值下,模型預測結果為正類、負類的樣本數,然後生成一組 (FPR, TPR)值,這樣就可以得到ROC曲線上的一點,最後將所有的點連接起來就出現了ROC曲線。
當閾值設置的次數越多,就會生成更多的 (FPR, TPR)值,畫出的ROC曲線也就越光滑。也就是說ROC曲線的光滑程度與閾值設置多少次相關。
所以,橫軸表示所有負樣本中,被錯誤預測為正的比例;縱軸表示所有正樣本中,被正確預測為正的比例。
我們當然希望正樣本被預測為正的比例越高越好,所以我們希望縱軸能往上!但是當縱軸的值TPR增加時,橫軸FPR同時也會增加。
意即門檻放寬,會導致越多某些負樣本被錯誤預測為正樣本。
ROC曲線越靠近左上角,表示效果越好。左上角座標為(0,1),即 FPR = 0,TPR = 1,這意味著FP(假陽性)=0,FN(假陰性)=0,這就是一個完美的模型,因為能夠對所有的樣本正確分類。
ROC曲線中的對角線(y=x)上的點表示模型的區分能力與亂猜就沒有差別。
AUC值
上述的判斷概念可以用面積量化,並拿來評估模型好壞,我們計算Area under the ROC curve,也就是俗稱的AUC值。在二元分類裡面,重點就是模型有沒有辦法有效的把兩類去分開來。
圖片來源 Finding Donors: Classification Project With PySpark
AUC值介於0-1之間,這裡給個經驗準則:
| AUC值 | 模型效果 |
|---|---|
| AUC = 1 | 完美 |
| 1 > AUC ≧ 0.9 | 很棒 |
| 0.9 > AUC ≧ 0.7 | 良好 |
| 0.7 > AUC ≧ 0.5 | 差強人意 |
| AUC = 0.5 | 等同亂猜 |
| AUC < 0.5 | 是否為反指標 |
接下來,我們來在R中實現ROC曲線與AUC值,這裡直接引用現成的套件ROCR。 ROCR套件中有現成的資料集,裡面分別是真實分類和預測機率。
#install.packages('ROCR')
#require(ROCR)
data(ROCR.simple)
kable(as.data.frame(ROCR.simple)[1:10, ]) %>% kable_styling() %>% column_spec(1:2,width = "20em") #為了方便只看前20筆資料| predictions | labels |
|---|---|
| 0.6125478 | 1 |
| 0.3642710 | 1 |
| 0.4321361 | 0 |
| 0.1402911 | 0 |
| 0.3848959 | 0 |
| 0.2444155 | 1 |
| 0.9706413 | 1 |
| 0.8901728 | 1 |
| 0.7817814 | 1 |
| 0.8687518 | 0 |
pred <- ROCR::prediction(ROCR.simple$predictions, ROCR.simple$labels)
perf <- ROCR::performance(pred,"tpr","fpr")
#算AUC值
auc <- performance(pred,'auc') %>% unlist() %>% slot("y.values") %>% unlist()
#出圖
plot(perf,colorize=TRUE,main=paste0("ROC Curve , AUC = ",round(auc,2)));abline(0,1);grid()KS曲線
接下來有個跟ROC曲線類似的圖,其基於Kolmogorov-Smirnov兩樣本檢驗的邏輯設計。
我們已經熟悉了ROC曲線怎麼畫了,接下來了解KS曲線與KS值就很容易。
ROC曲線中,橫軸是假正率FPR,縱軸是真正率TPR,線上每一點是不同門檻值對應到的(FPR,TPR)組合。而KS曲線中,我們把假正率也拉到縱軸,獨立變成另一條曲線,縱軸就是兩個值的累積分布函數,而原本的橫軸則為門檻值(預測為正的機率值)。整張圖詮釋預測機率從小到大,正率與負率的變動,計算兩條曲線的差值取最大的作為KS值。
KS值是模型將正樣本和負樣本區分開來的最大分類能力。KS值越大,表示模型能夠將正、負分類分開的程度越大,模型的預測準確性越好。KS值的範圍是[0,1]。KS值大於0.2時,即可認為模型預測準確性達到可用要求。一般模型KS值介於0.2到0.6之間,很難超過0.6。
由於KS值能找出模型中差異最大的一個門檻值,因此也適合用來找門檻值cut off。但是KS值只能反映出哪個門檻值是區分最大的,較不能總體反映出總體模型的分類效果,這點AUC值更能勝任。不過單單比較兩個模型的KS值,也仍然能當作分類能力的參考。如果模型中採用的Feature不佳,沒辦法有效分類樣本,那麼AUC值就會很低,不管門檻值怎麼調都不會好。
承接ROC圖,這裡繼續使用ROCR包繪圖,這裡先以門檻值為底。
perf <- ROCR::performance(pred,"tpr","fpr")
FPR=attr(perf,'x.values')[[1]]
TPR=attr(perf,'y.values')[[1]]
Cutoff=attr(perf,'alpha.values')[[1]]
ks_df <- data.frame(FPR,TPR,Cutoff,KS=TPR-FPR)
ks_max <- max(ks_df$KS)
plotKS <- ggplot(ks_df)+
geom_line(aes(Cutoff,TPR),colour="red2",size=1.2)+
geom_line(aes(Cutoff,FPR),colour="blue3",size=1.2)+
geom_line(aes(Cutoff,TPR-FPR),colour="forestgreen",size=1.2)+
geom_vline(xintercept=ks_df[ks_df$KS==ks_max,"Cutoff"],linetype=2,colour="gray",size=0.6)+
geom_hline(yintercept=ks_df[ks_df$KS==ks_max,"TPR"],linetype=2,colour="red2",size=0.6)+
geom_hline(yintercept=ks_df[ks_df$KS==ks_max,"FPR"],linetype=2,colour="blue3",size=0.6)+
geom_hline(yintercept=ks_df[ks_df$KS==ks_max,"KS"],linetype=2,colour="forestgreen",size=0.6)+
geom_text(aes(x = 0.25, y = 1.0, label = "TPR"),colour="red2") +
geom_text(aes(x = 0.125, y = 0.60, label = "FPR"), colour = "blue3") +
xlab("Cutoff")+
ylab("TPR & FRP")+
ggtitle(label="KS - Chart")+
theme_bw()+
theme(plot.title=element_text(colour="gray24",size=12,face="bold"),
plot.background = element_rect(fill = "gray90"),
axis.title=element_text(size=10),
axis.text=element_text(colour="gray35"),
legend.position = "right")
plotKS
但實際的KS圖,會改用預測機率的百分比作為橫軸,陽性或陰性的累積佔比為Y軸,而為什麼不用上面的畫法呢?
因為門檻值對應到樣本被預測出來的機率,如果機率多集中在某些值附近,就無法畫出如上圖從門檻值0開始到1都還算滑順的圖。
因此實際作法如下:
1. 模型產出預測為陽性的機率值,我們先將資料已此機率值由大到小排序。
2. 依排序後的機率值由大到小算出不同的百分位數。 預測機率的百分位數,理解為Depth = proportion allocated to class positive,預測成正例的比例 Depth=25,表示所有樣本中有百分之25被歸納為陽性。
舉個例: 如果我有一組資料的預測機率由大到小排序為[0.99,0.87,0.75,0.54,0.49,0.43,0.36,0.21,0.15,0.07]
而其對應的標籤為[1,1,1,1,0,0,0,0,0,0]
這時候我們把門檻值設定成0.99以上才能被歸類是陽性,整個10筆預測中,只有一筆會被歸納成是正類。
不管預測結果是對是錯,被歸納為陽性的筆數/總筆數,我們可以算出這時候佔比為1/10=10%
被預測為正的1筆中,因此被判斷正確的陽性為1/4,被錯誤判斷的陽性為0/4。 之後降低門檻值,會讓更多資料被歸納為陽性,隨著百分位數繼續增加,累積成功佔比和累積失敗佔比會不斷累積而成長。
接下來也示範一下,不使用ROCR計算TPR、FPR,而是自己手刻的寫法。
ks.plot = function(prediction,label,n=100){
df <- data.frame(prediction,label) %>% arrange(desc(prediction))
total_positive <- sum(df$label)
total_negative <- nrow(df)-total_positive
# n代表將機率區間0-1要等比例分成幾份
# 如果有超過100個樣本,則切100份,否則,分割數等同於樣本個數
if(n > nrow(df)){n <- nrow(df)}
df$rownum <- 1:nrow(df)
qus <- quantile(1:nrow(df),probs=seq(0,1,1/n)) #把原本的總比數切成n份
success_prop <- failure_prop <- NULL
out <- mapply(function(i){
sub_df <- df[df$rownum < ifelse(i==n,qus[i+1]+0.001,qus[i+1]),] #隨著機率遞減
success_prop <<-c(success_prop,sum(sub_df$label==1)) #實際為1的累積個數
failure_prop <<-c(failure_prop,sum(sub_df$label==0)) #實際為0的累積個數
},1:n)
success_prop <- success_prop/total_positive
failure_prop <- failure_prop/total_negative
ks_df <- data.frame(rownum=1:n,success_prop,failure_prop,KS=success_prop-failure_prop)
ks_max <- max(ks_df$KS)
# 繪製曲線
plotKS <- ggplot()+
geom_line(aes(ks_df$rownum,ks_df$success_prop),colour="red2",size=1.2)+
geom_line(aes(ks_df$rownum,ks_df$failure_prop),colour="blue3",size=1.2)+
geom_line(aes(ks_df$rownum,ks_df$KS),colour="forestgreen",size=1.2)+
geom_vline(xintercept=ks_df[ks_df$KS==ks_max,"rownum"],linetype=2,colour="gray",size=0.6)+
geom_hline(yintercept=ks_df[ks_df$KS==ks_max,"success_prop"],linetype=2,colour="red2",size=0.6)+
geom_hline(yintercept=ks_df[ks_df$KS==ks_max,"failure_prop"],linetype=2,colour="blue3",size=0.6)+
geom_hline(yintercept=ks_df[ks_df$KS==ks_max,"KS"],linetype=2,colour="forestgreen",size=0.6)+
annotate("text", x = 10, y = 1.05, label=paste("KS=", round(ks_max, 4)), size=4,alpha=0.8)+
geom_text(aes(x = 75, y = 1.0, label = "TPR"),colour="red2") +
geom_text(aes(x = 80, y = 0.6, label = "FPR"), colour = "blue3") +
xlab("% allocated to class positive")+
ylab("Cumulative proportion")+
ggtitle(label="KS - Chart")+
theme_bw()+
theme(plot.title=element_text(colour="gray24",size=12,face="bold"),
plot.background = element_rect(fill = "gray90"),
axis.title=element_text(size=10),
axis.text=element_text(colour="gray35"))
return(list(plotKS=plotKS,ks_max=ks_max))
}
ks.plot(ROCR.simple$predictions,ROCR.simple$labels,100)## $plotKS
##
## $ks_max
## [1] 0.6905839
由結果可知,兩個方法算出來的KS值相同。
前一張用cutoff門檻值當X軸,而每一個門檻值的取值都是實際被預測出來的機率,若這個預測出來的機率值本身分布不均,就無法看到趨勢。 而下圖是用百分位數的方法呈現,是把機率做排名之後用百分位數依序表示,不受原本機率值分布情形影響。
Gain 累積增益圖 / Lift 累積提升圖
跟上圖同樣原理,我們把縱軸的指標換一下,換成Gain值和Lift值,可以得到累積增益圖和累積提升圖。
橫軸一樣是總樣本數中預測成陽性的比例,就是上面講的Depth,也被表示成Rate of Positive Predictions
\[RPP(Rate\ of\ positive\ predictions) =\frac{TP+FP}{P+N}\] 當門檻值不同時,RPP會變動,其值範圍為[0,1]。
累積增益圖其實就是KS圖只留下TPR那條線,Gain為所有正類中,成功被分類為正的比例,增益圖反映門檻值設定不同時,對應到的不同召回率。 \[Gain=\frac{TP}{TP+FN}\]
另外,提升值(Lift Value)則進一步考慮了在某個RPP下的TPR(Recall) \(TPR=\frac{TP}{TP+FN} \)的這個相對性概念,用TPR/RPP計算。
\[Lift=\frac{\frac{TP}{TP+FN}}{\frac{TP+FP}{P+N}}\]
這裡就偷懶,直接用ROCR的功能來產!
pred <- ROCR::prediction(ROCR.simple$predictions, ROCR.simple$labels)
gain <- ROCR::performance(pred, "tpr", "rpp")
plot(gain, main = "Gain Chart",col = "red2", lwd = 3)lift <- ROCR::performance(pred,"lift","rpp")
plot(lift, main = "Lift Chart",col = "red2", lwd = 3)Response 累積回應圖
所謂回應,可以用個簡單的例子說明。
如果針對100個客戶進行行銷,其中5位參與,回應率就是5%。
那我們實際為正的個數除以模型分類出來為正的個數比值,就是回應Response值。 累積回應圖就是基於各分位數Depth對應區間中的回應率繪製的。 結果會跟Lift圖很類似,只是縱軸的尺度不一樣。
pred <- ROCR::prediction(ROCR.simple$predictions, ROCR.simple$labels)
response <- ROCR::performance(pred,"ppv","rpp")
plot(response, main = "Response Chart",col = "red2", lwd = 3)參考資料:
程式前沿
ITread
Tommy大的Medium
Rstudio for ROC curves
Binary Classifier evaluation
如果內容有任何問題或錯誤,歡迎來信跟我聯絡唷! ivan0628@gmail.com