機器學習簡易入門(二) - 分類
摘要:本文簡單敘述了如何通過分類算法來評估銀行發放貸款的模型
聲明:(本文的內容非原創,但經過本人翻譯和總結而來,轉載請注明出處)
本文內容來源:https://www.dataquest.io/mission/57/classification-basics
在你向銀行申請信用卡或者貸款時,銀行會使用根據過往的數據所建立的模型,再根據你的實際情況來決定是否接受你的申請。
原始數據展現
銀行在以往的某段時間為了訓練這個評分模型,向所有申請者都發放了貸款,然后記錄全部人是否有還款以及他們的評分情況,paid字段表明該申請人是否有如實還款,1是正常還款,0是違約。model_score字段表明該申請人在獲得貸款前在評分模型中的得分
import pandas credit = pandas.read_csv("credit.csv")
評估模型
根據上面的歷史數據,找到適合的閥值(model_score究竟為多少分時才接受貸款申請),然后獲取最大的利潤
准確率
我們通過設置一個model_score的閥值來決定是否接受貸款申請,如果該申請者的model_score大於該閥值就接受,反之亦然,通過控制這個閥值來控制新客戶量。衡量一個模型的准確性是通過公示:准確率 = 正確預測數 / 樣本總量
# 設置閥值為0.5,計算這個模型的准確率(評分大於0.5,且如實還款) pred = credit["model_score"] > 0.5 accuracy = sum(pred == credit["paid"]) / len(pred) # paid字段為1,且model_score大於0.5
這個結果表明如果只向model_score大於0.5的申請者發放貸款,大概會有86%的人還款
混淆矩陣
下表描述二元分類問題的混淆矩陣,表中每個表項Fij表示實際類標號為i但被預測為類j的記錄數,例如,F01代表原本屬於類0但被誤分為類1的記錄數,按照混淆矩陣中的表項,被分類模型正確預測的樣本總數是(F11 + F00),而被錯誤預測的樣本總數是(F10 + F01)
|
預測的類 |
||
類 = 1 |
類 = 0 |
||
實際的類 |
類 = 1 |
F11 |
F10 |
類 = 0 |
F01 |
F00 |
在本文中的混淆矩陣是這樣的
|
實際上會還款 |
實際上不會還款 |
預測會還款 |
TP |
FP |
預測不會還款 |
FN |
TN |
真正(True Positive , TP)被模型預測為正的正樣本;
假負(False Negative , FN)被模型預測為負的正樣本;
假正(False Positive , FP)被模型預測為正的負樣本;
真負(True Negative , TN)被模型預測為負的負樣本
真正率(True Positive Rate , TPR)或靈敏度(sensitivity):TPR = TP /(TP + FN) (正樣本預測結果數 / 正樣本實際數)
假負率(False Negative Rate , FNR):FNR = FN /(TP + FN) (被預測為負的正樣本結果數 / 正樣本實際數 )
假正率(False Positive Rate , FPR):FPR = FP /(FP + TN) (被預測為正的負樣本結果數 /負樣本實際數)
真負率(True Negative Rate , TNR)或特指度(specificity):TNR = TN /(TN + FP) (負樣本預測結果數 / 負樣本實際數)
# 把閥值設置為0.5,分別計算上面的混淆矩陣 TP = sum(((credit['model_score'] > 0.5) == 1) & (credit['paid'] == 1)) FN = sum(((credit['model_score'] <= 0.5) == 1) & (credit['paid'] == 1)) FP = sum(((credit['model_score'] > 0.5) == 1) & (credit['paid'] == 0)) TN = sum(((credit['model_score'] <= 0.5) == 1) & (credit['paid'] == 0))
只要我們的模型中真正率(TPR)大於假正率(FPR),就能保證還款的人要比違約的人多,從而保證銀行不會虧本
計算ROC曲線
ROC曲線(receiver operating characteristic curve),又稱為感受性曲線(sensitivity curve)。得此名的原因在於曲線上各點反映着相同的感受性,它們都是對同一信號刺激的反應,只不過是在幾種不同的判定標准下所得的結果而已。接受者操作特性曲線就是以虛驚概率為橫軸,擊中概率為縱軸所組成的坐標圖,和被試在特定刺激條件下由於采用不同的判斷標准得出的不同結果畫出的曲線
根據上文所述,現在要尋找一個閥值,使得真正率大於假正率
import numpy def roc_curve(observed, probs): # 將閥值由1到0,分成100個小數 thresholds = numpy.asarray([(100-j)/100 for j in range(100)]) # 初始化為全0 fprs = numpy.asarray([0. for j in range(100)]) tprs = numpy.asarray([0. for j in range(100)]) # 對每個閥值進行循環 for j, thres in enumerate(thresholds): pred = probs > thres FP = sum((observed == 0) & (pred == 1)) TN = sum((observed == 0) & (pred == 0)) FPR = float(FP / (FP + TN)) TP = sum((observed == 1) & (pred == 1)) FN = sum((observed == 1) & (pred == 0)) TPR = float(TP / (TP + FN)) fprs[j] = FPR tprs[j] = TPR return fprs, tprs, thresholds fpr, tpr, thres = roc_curve(credit["paid"], credit["model_score"]) idx = numpy.where(fpr>0.20)[0][0] # 選擇假正率為0.2的閥值,理由在下面 print('FPR: 0.2') print('TPR: {}'.format(tpr[idx])) print('Threashold: {}'.format(thres[idx])) # 以假正率做x軸,真正率做y軸作圖 plt.plot(fpr, tpr) plt.xlabel('FPR') plt.ylabel('TPR') plt.show()
說明了當閥值設置為0.38時,FPR = 0.2,TPR = 0.93
在上圖中可見,當FPR(假正率)達到了0.2之后,整條曲線都變平了,也就是說當FPR大於0.2之后,違約的人數增加了,不違約的人數卻沒有增加多少。
計算AUC
如果用兩個模型分別作出了不同的ROC曲線,那么要怎樣對比這兩條ROC曲線的優異程度呢?可以使用AUC,AUC通過測量ROC曲線下面的面積來獲得。如果一個模型是完美的,那么他的TPR就會是1,所以AUC也是1,而如果一個模型的TPR是0那么AUC也會是0.所以可以通過比較AUC的大小來比較兩個模型的優異,越高的AUC意味着模型越完美
可以通過roc_auc_score函數來計算
#一個簡單的例子 from sklearn.metrics import roc_auc_score probs = [ 0.98200848, 0.92088976, 0.13125231, 0.0130085, 0.35719083, 0.34381803, 0.46938187, 0.53918899, 0.63485958, 0.56959959] obs = [1, 1, 0, 0, 1, 0, 1, 0, 0, 1] testing_auc = roc_auc_score(obs, probs) print("Example AUC: {auc}".format(auc=testing_auc))
計算本文的AUC
auc = roc_auc_score(credit["paid"], credit["model_score"])
召回率和准確率
除了上面用來計算ROC的TPR和FPR之外,還有兩個重要的指標:正確率(precision)和召回率(recall)
在本文中,越高的正確率說明在發放貸款之后,還款率要比違約率高,越高的召回率說明潛在客戶(那些有能力還款,但是被銀行拒絕了發放貸款)的流失率越低
# 以閥值0.5來計算 pred = credit["model_score"] > 0.5 # True Positives TP = sum(((pred == 1) & (credit["paid"] == 1))) # False Positives FP = sum(((pred == 0) & (credit["paid"] == 1))) # False Negatives FN = sum(((pred == 1) & (credit["paid"] == 0))) precision = TP / (TP + FP) recall = TP / (TP + FN) print('precision: {}'.format(precision)) print('recall: {}'.format(recall))
類似於ROC曲線,作出正確率與召回率曲線
from sklearn.metrics import precision_recall_curve precision, recall, thresholds = precision_recall_curve(credit["paid"], credit["model_score"]) plt.plot(recall, precision) plt.xlabel('Recall') plt.ylabel('Precision') plt.show()
在上圖中,曲線在Recall = 0.8的時候才陡然下降,此時的Precision = 0.9,說明了此時只流失了少量的潛在客戶,同時違約率也很低