風控(一):ROC曲線和K-S曲線比較及python實現


1.混淆矩陣(一級指標)

以分類模型中最簡單的二分類為例,對於這種問題,我們的模型最終需要判斷樣本的結果是0還是1,或者說是positive還是negative。我們通過樣本的采集,能夠直接知道真實情況下,哪些數據結果是positive,哪些結果是negative。同時,我們通過用樣本數據跑出分類型模型的結果,也可以知道模型認為這些數據哪些是positive,哪些是negative。因此,我們就能得到這樣四個基礎指標,我稱他們是一級指標(最底層的):

  • 真實值是positive,模型認為是positive的數量(True Positive=TP)
  • 真實值是positive,模型認為是negative的數量(False Negative=FN):這就是統計學上的第一類錯誤(Type I Error)
  • 真實值是negative,模型認為是positive的數量(False Positive=FP):這就是統計學上的第二類錯誤(Type II Error)
  • 真實值是negative,模型認為是negative的數量(True Negative=TN)

 

 注:T肯定是對的,F是錯的。

 預測性分類模型,肯定是希望越准越好。那么,對應到混淆矩陣中,那肯定是希望TP與TN的數量大,而FP與FN的數量小。所以當我們得到了模型的混淆矩陣后,就需要去看有多少觀測值在第二、四象限對應的位置,這里的數值越多越好;反之,在第一、三象限對應位置出現的觀測值肯定是越少越好。

2.二級指標

但是,混淆矩陣里面統計的是個數,有時候面對大量的數據,光憑算個數,很難衡量模型的優劣。因此混淆矩陣在基本的統計結果上又延伸了如下4個指標,我稱他們是二級指標(通過最底層指標加減乘除得到的):

  • 准確率(Accuracy)—— 針對整個模型
  • 精確率(Precision)
  • 靈敏度(Sensitivity):就是召回率(Recall)
  • 特異度(Specificity)

可以將混淆矩陣中數量的結果轉化為0-1之間的比率。便於進行標准化的衡量。

3.三級指標

在這四個指標的基礎上在進行拓展,會產令另外一個三級指標這個指標叫做F1 Score。他的計算公式是:

其中,P代表Precision,R代表Recall。

F1-Score指標綜合了Precision與Recall的產出的結果。F1-Score的取值范圍從0到1的,1代表模型的輸出最好,0代表模型的輸出結果最差。

4.ROC曲線

ROC曲線:Receiver Operating Characteristic曲線,橫軸是FPR(False Positive Rate),縱軸是TPR(True Positive Rate)。

AUC(Area Under ROC Curve):ROC曲線下的面積。

5.K-S曲線

洛倫茲曲線(Kolmogorov-Smirnov curve)值越大,表示模型能夠將正、負客戶區分開的程度越大。KS值的取值范圍是[0,1] 。

KS曲線是兩條線,其橫軸是閾值,縱軸是TPR(上面那條)與FPR(下面那條)的值,值范圍[0,1] 。兩條曲線之間之間相距最遠(差)的地方對應的閾值,就是最能划分模型的閾值。繪制過程如下:

 可以看出,在閾值等於0.4的地方,TPR和FPR差最大,說明該處閾值可作為最佳區分點。

6.相關代碼

6.1 混淆矩陣pyspark

 1 '''
 2 TP(True Positive):真實為1,預測為1 
 3 FN(False Negative):真實為1,預測為0 
 4 FP(False Positive):真實為0,預測為1 
 5 TN(True Negative):真實為0,預測為0 
 6 '''
 7 #訓練集
 8 a=0.1
 9 result_train_tmp=result_train.withColumn("tp",F.expr("""case when label=1 and round(prediction+{a},0)=1 then 1 else 0 end""".format(a=a))).\
10                               withColumn("fn",F.expr("""case when label=1 and round(prediction+{a},0)=0 then 1 else 0 end""".format(a=a))).\
11                               withColumn("fp",F.expr("""case when label=0 and round(prediction+{a},0)=1 then 1 else 0 end""".format(a=a))).\
12                               withColumn("tn",F.expr("""case when label=0 and round(prediction+{a},0)=0 then 1 else 0 end""".format(a=a)))
View Code

6.2 ROC曲線python

import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams.update({'font.size': 10})
plt.rcParams['savefig.dpi'] = 300 #圖片像素
plt.rcParams['figure.dpi'] = 300 #分辨率

# 預測
y_pred_lr=lr.predict_proba(x_test)
# 計算AUC
fpr_lr,tpr_lr,thresholds = roc_curve(y_test,y_pred_lr[:,1],pos_label=1)
roc_auc_lr = auc(fpr_lr, tpr_lr)

# 繪制roc
plt.rcParams['figure.figsize']=(8,5)
plt.figure()
plt.plot(fpr_lr, tpr_lr, color='darkorange', label='ROC curve (area = %0.2f)' % roc_auc_lr)
plt.plot([0, 1], [0, 1], color='navy', 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('ROC曲線-LR')
plt.legend(loc="lower right")


#-------------------------------------------------

#交叉驗證畫roc
from sklearn.model_selection  import KFold

kf=KFold(n_splits=5)
fig=plt.figure(figsize=(7,5))
mean_tpr=0.0
mean_fpr=np.linspace(0,1,100)
all_tpr=[]
x_train=np.array(x_train)
y_train=np.array(y_train)
i=0
for train_index,test_index in kf.split(x_train):
    model=gbdt.fit(x_train[train_index],y_train[train_index])
    probas=model.predict_proba(x_train[test_index])
    fpr,tpr,thresholds = roc_curve(y_train[test_index],probas[:,1],pos_label=1)
    mean_tpr+=np.interp(mean_fpr,fpr,tpr)
    mean_tpr[0]=0.0
    roc_auc = auc(fpr,tpr)
    plt.plot(fpr,tpr,lw=1,label='ROC fold %d (area = %0.2f)'%(i+1,roc_auc))
    i+=1
    
plt.plot([0,1],[0,1],linestyle='--',color=(0.6,0.6,0.6),label='random guessing')
mean_tpr/=5
mean_tpr[-1]=1.0
mean_auc=auc(mean_fpr,mean_tpr)
plt.plot(mean_fpr,mean_tpr,'k--',label='mean ROC (area=%0.2f)'%mean_auc,lw=2)
plt.plot([0,0,1],[0,1,1],lw=2,linestyle=':',color='black',label='perfect performance')
plt.xlim([-0.05,1.05])
plt.ylim([-0.05,1.05])
plt.xlabel('false positive rate')
plt.ylabel('true positive rate')
plt.title('Receiver Operator Characteristic')
plt.legend(loc='lower right')
plt.show()
View Code

6.3 K-S曲線python

 1 # 繪制K-S曲線
 2 import numpy as np
 3 import pandas as pd
 4 def PlotKS(preds, labels, n, asc):
 5     
 6     # preds is score: asc=1
 7     # preds is prob: asc=0
 8     # n為划分閾值的個數,10為0-1
 9     
10     pred = preds  # 預測值
11     bad = labels  # 取1為bad, 0為good
12     ksds = pd.DataFrame({'bad': bad, 'pred': pred})
13     ksds['good'] = 1 - ksds.bad
14     
15     if asc == 1:
16         ksds1 = ksds.sort_values(by=['pred', 'bad'], ascending=[True, True])
17     elif asc == 0:
18         ksds1 = ksds.sort_values(by=['pred', 'bad'], ascending=[False, True])
19     ksds1.index = range(len(ksds1.pred))
20     ksds1['cumsum_good1'] = 1.0*ksds1.good.cumsum()/sum(ksds1.good)
21     ksds1['cumsum_bad1'] = 1.0*ksds1.bad.cumsum()/sum(ksds1.bad)
22     
23     if asc == 1:
24         ksds2 = ksds.sort_values(by=['pred', 'bad'], ascending=[True, False])
25     elif asc == 0:
26         ksds2 = ksds.sort_values(by=['pred', 'bad'], ascending=[False, False])
27     ksds2.index = range(len(ksds2.pred))
28     ksds2['cumsum_good2'] = 1.0*ksds2.good.cumsum()/sum(ksds2.good)
29     ksds2['cumsum_bad2'] = 1.0*ksds2.bad.cumsum()/sum(ksds2.bad)
30     
31     # ksds1 ksds2 -> average
32     ksds = ksds1[['cumsum_good1', 'cumsum_bad1']]
33     ksds['cumsum_good2'] = ksds2['cumsum_good2']
34     ksds['cumsum_bad2'] = ksds2['cumsum_bad2']
35     ksds['cumsum_good'] = (ksds['cumsum_good1'] + ksds['cumsum_good2'])/2
36     ksds['cumsum_bad'] = (ksds['cumsum_bad1'] + ksds['cumsum_bad2'])/2
37     
38     # ks
39     ksds['ks'] = ksds['cumsum_bad'] - ksds['cumsum_good']
40     ksds['tile0'] = range(1, len(ksds.ks) + 1)
41     ksds['tile'] = 1.0*ksds['tile0']/len(ksds['tile0'])
42     
43     qe = list(np.arange(0, 1, 1.0/n))
44     qe.append(1)
45     qe = qe[1:]
46     
47     ks_index = pd.Series(ksds.index)
48     ks_index = ks_index.quantile(q = qe)
49     ks_index = np.ceil(ks_index).astype(int)
50     ks_index = list(ks_index)
51     
52     ksds = ksds.loc[ks_index]
53     ksds = ksds[['tile', 'cumsum_good', 'cumsum_bad', 'ks']]
54     ksds0 = np.array([[0, 0, 0, 0]])
55     ksds = np.concatenate([ksds0, ksds], axis=0)
56     ksds = pd.DataFrame(ksds, columns=['tile', 'cumsum_good', 'cumsum_bad', 'ks'])
57     
58     ks_value = ksds.ks.max()
59     ks_pop = ksds.tile[ksds.ks.idxmax()]
60     print ('ks_value is ' + str(np.round(ks_value, 4)) + ' at pop = ' + str(np.round(ks_pop, 4)))
61     
62     # chart
63 
64     # chart
65     plt.plot(ksds.tile, ksds.cumsum_good, label='cum_good',
66                          color='blue', linestyle='-', linewidth=2)
67                          
68     plt.plot(ksds.tile, ksds.cumsum_bad, label='cum_bad',
69                         color='red', linestyle='-', linewidth=2)
70                         
71     plt.plot(ksds.tile, ksds.ks, label='ks',
72                    color='green', linestyle='-', linewidth=2)
73                        
74     plt.axvline(ks_pop, color='gray', linestyle='--')
75     plt.axhline(ks_value, color='green', linestyle='--')
76     plt.axhline(ksds.loc[ksds.ks.idxmax(), 'cumsum_good'], color='blue', linestyle='--')
77     plt.axhline(ksds.loc[ksds.ks.idxmax(),'cumsum_bad'], color='red', linestyle='--')
78     plt.title('KS=%s ' %np.round(ks_value, 4) +  
79                 'at Pop=%s' %np.round(ks_pop, 4), fontsize=15)
80     
81 
82     return ksds
View Code

6.4 其他指標計算python

1 from sklearn.metrics import precision_score, recall_score, f1_score,accuracy_score
2 
3 acc=accuracy_score(y_test, y_pred_lr_new)
4 p = precision_score(y_test, y_pred_lr_new, average='binary')
5 r = recall_score(y_test, y_pred_lr_new, average='binary')
6 f1score = f1_score(y_test, y_pred_lr_new, average='binary')
7 print(acc,p,r,f1score)
View Code

 

相關鏈接:

混淆矩陣:https://blog.csdn.net/Orange_Spotty_Cat/article/details/80520839

ROC曲線繪制:https://blog.csdn.net/cymy001/article/details/79613787


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM