give me some Creadit 信用評分卡案例

#1、數據準備git

     #目標及背景算法

     #數據的獲取與整合api

#2、數據處理less

     #一、基礎的處理dom

     #二、缺失值及處理ide

         #最近鄰(kNN,k-NearestNeighbor)分類算法函數

     #三、異常值的分析及處理性能

         #a、單變量異常值檢測測試

         #b、使用LOF(局部異常因子)檢查異常值ui

         #c、聚類檢測異常值

#3、單變量分析

    #一、單變量分析

    #二、變量之間的相關性

#4、切分數據集

#5、Logistic迴歸

     #一、基本公式

    #二、創建模型

     #三、模型評估

         #混淆矩陣

         #ROC曲線

         #AUC(Area Under Curve)

#6、WOE轉換

     #一、進行分箱

     #二、計算WOE值

     #三、對變量進行WOE變換

     #四、WOE DataFrame構建:

#7、評分卡的建立和實施

     #邏輯迴歸建模

     #一、對各變量進行打分

         #構造計算分值函數

     #二、計算各變量分箱得分:

     #三、最終生成的評分卡以下:

     #四、我的評分計算案例

 

 

  • 1、數據準備

     目標及背景

a、信用評分算法,對默承認能性進行猜想,這是銀行用來判斷貸款是否應該被授予的方法,完成一個評分卡,經過預測某人在將來兩年將會經歷財務危機的可能性來提升信用評分的效果,幫助貸款人作出最好的決策

b、 首先是基於我的借貸的場景,肯定「違約」的定義: 根據新的Basel II Capital Accord(巴塞爾二資本協議),通常逾期90天算做違約

 

    數據的獲取與整合

數據來源:數據來自Kaggle,cs-training.csv是有15萬條的樣本數據,下圖能夠看到這份數據的大體狀況。下載地址爲:https://www.kaggle.com/c/GiveMeSomeCredit/data

數據描述:數據屬於我的消費類貸款,只考慮評分卡最終實施時可以使用到的數據應從以下一些方面獲取數據

基本屬性:包括了借款人當時的年齡。

償債能力:包括了借款人的月收入、負債比率。

信用往來:兩年內35-59天逾期次數、兩年內60-89天逾期次數、兩年內90天或高於90天逾期的次數。

財產情況:包括了開放式信貸和貸款數量、不動產貸款或額度數量。

貸款屬性:暫無。

其餘因素:包括了借款人的家眷數量(不包括本人在內)。

變量介紹:

變量名 變量描述  
SeriousDlqin2yrs 超過90天或者更糟的逾期拖欠 y
RevolvingUtilizationOfUnsecuredLines 循環貸款無抵押額度 x1
age 借款人當時的年齡 x2
NumberOfTime30.59DaysPastDueNotWorse 35-59天逾期但不糟糕次數 x3
DebtRatio 負債比率 x4
MonthlyIncome 月收入 x5
NumberOfOpenCreditLinesAndLoans 開放式信貸和貸款數量,開放式貸款(分期付款如汽車貸款或抵押) x6
NumberOfTimes90DaysLate 90天逾期次數:借款者有90天或更高逾期的次數 x7
NumberRealEstateLoansOrLines 不動產貸款或額度數量:抵押貸款和不動產放款包括房屋淨值信貸額度 x8
NumberOfTime60.89DaysPastDueNotWorse 60-89天逾期但不糟糕次數:借款人在在過去兩年內有60-89天逾期還款但不糟糕的次數 x9
NumberOfDependents 家眷數量:不包括本人在內的家眷數量 x10
$ X                                   : int  1 2 3 4 5 6 7 8 9 10 ...   #序號
 $ SeriousDlqin2yrs                    : int  1 0 0 0 0 0 0 0 0 0 ...  #超過90天或者更糟的逾期拖欠
 $ RevolvingUtilizationOfUnsecuredLines: num  0.766 0.957 0.658 0.234 0.907 ...  #‘循環貸款無抵押額度
 $ age                                 : int  45 40 38 30 49 74 57 39 27 57 ... #借款人當時的年齡
 $ NumberOfTime30.59DaysPastDueNotWorse: int  2 0 1 0 1 0 0 0 0 0 ...  #35-59天逾期但不糟糕次數
 $ DebtRatio                           : num  0.803 0.1219 0.0851 0.036 0.0249 ... #負債比率
 $ MonthlyIncome                       : int  9120 2600 3042 3300 63588 3500 NA 3500 NA 23684 ... #月收入
 $ NumberOfOpenCreditLinesAndLoans     : int  13 4 2 5 7 3 8 8 2 9 ... #開放式信貸和貸款數量,開放式貸款(分期付款如汽車貸款或抵押)
 $ NumberOfTimes90DaysLate             : int  0 0 1 0 0 0 0 0 0 0 ... #90天逾期次數:借款者有90天或更高逾期的次數
 $ NumberRealEstateLoansOrLines        : int  6 0 0 0 1 1 3 0 0 4 ...#不動產貸款或額度數量:抵押貸款和不動產放款包括房屋淨值信貸額度
 $ NumberOfTime60.89DaysPastDueNotWorse: int  0 0 0 0 0 0 0 0 0 0 ...#60-89天逾期但不糟糕次數:借款人在在過去兩年內有60-89天逾期還款但不糟糕的次數
 $ NumberOfDependents                  : int  2 1 0 0 0 1 0 0 NA 2 ...#家眷數量:不包括本人在內的家眷數量

 

  • 2、數據處理

    一、基礎處理

    去掉數據中的序號,即第一列,要預測 SeriousDlqin2yrs變量,所以將其設置爲y,其餘的設置爲x1~x10,這樣做圖時方便顯示變量

> traindata <- read.csv('C:\\Users\\Xu\\Desktop\\give me some Credit\\cs-training.csv')
> traindata <- traindata[,-1] #去除第一列序號
> str(traindata)
'data.frame':	150000 obs. of  11 variables:
 $ SeriousDlqin2yrs                    : int  1 0 0 0 0 0 0 0 0 0 ...
 $ RevolvingUtilizationOfUnsecuredLines: num  0.766 0.957 0.658 0.234 0.907 ...
 $ age                                 : int  45 40 38 30 49 74 57 39 27 57 ...
 $ NumberOfTime30.59DaysPastDueNotWorse: int  2 0 1 0 1 0 0 0 0 0 ...
 $ DebtRatio                           : num  0.803 0.1219 0.0851 0.036 0.0249 ...
 $ MonthlyIncome                       : int  9120 2600 3042 3300 63588 3500 NA 3500 NA 23684 ...
 $ NumberOfOpenCreditLinesAndLoans     : int  13 4 2 5 7 3 8 8 2 9 ...
 $ NumberOfTimes90DaysLate             : int  0 0 1 0 0 0 0 0 0 0 ...
 $ NumberRealEstateLoansOrLines        : int  6 0 0 0 1 1 3 0 0 4 ...
 $ NumberOfTime60.89DaysPastDueNotWorse: int  0 0 0 0 0 0 0 0 0 0 ...
 $ NumberOfDependents                  : int  2 1 0 0 0 1 0 0 NA 2 ...
 
> colnames(traindata) <- c('y','x1','x2','x3','x4','x5','x6','x7','x8','x9','x10')
> head(traindata)
  y        x1 x2 x3         x4    x5 x6 x7 x8 x9 x10
1 1 0.7661266 45  2 0.80298213  9120 13  0  6  0   2
2 0 0.9571510 40  0 0.12187620  2600  4  0  0  0   1
3 0 0.6581801 38  1 0.08511338  3042  2  1  0  0   0
4 0 0.2338098 30  0 0.03604968  3300  5  0  0  0   0
5 0 0.9072394 49  1 0.02492570 63588  7  0  1  0   0
6 0 0.2131787 74  0 0.37560697  3500  3  0  1  0   1

 

      二、缺失值及處理

     觀察數據的分佈狀況,不少模型對缺失值敏感

library(VIM)
matrixplot(traindata) #缺失值可視化淺色表示值小,深色表示值大,而默認缺失值爲紅色

    martrixplot函數對缺失值部分進行但是可視化展現,淺色表示值小,深色表示值大,缺失值爲紅色,能夠看到x5( MonthlyIncome),x10( NumberOfDependents)存在卻缺失值,能夠具體看下數值

> library(mice)
> md.pattern(traindata) #查看具體的缺失值
       y x1 x2 x3 x4 x6 x7 x8 x9  x10    x5      
120269 1  1  1  1  1  1  1  1  1    1     1     0
 25807 1  1  1  1  1  1  1  1  1    1     0     1
  3924 1  1  1  1  1  1  1  1  1    0     0     2
       0  0  0  0  0  0  0  0  0 3924 29731 33655

完整的觀測有1202條,x5缺失爲29731,x10缺失爲3924。    

         最近鄰(kNN,k-NearestNeighbor)分類算法

    缺失值的處理方法不少,例如基於聚類的方法,基於迴歸的方法,基於均值的方法,固然能夠刪除,本文中由於缺失值所佔比例較高,不適合移除,使用KNN方法來對缺失值進行填補

> library(DMwR)
> traindata <- knnImputation(traindata,k=10,meth='weighAvg')
> traindata1 <- traindata #先賦值下數據處理的數據,免的數據搞丟又要從新處理,花費很長的時間

    三、異常值的分析及處理

    關於異常值的檢測,這裏簡單介紹下一些檢測方法

     a、單變量異常值檢測

    在R語言中可以使用 boxplot.stats()能夠實現 單變量檢測,該函數更具返回的統計數據生成箱線圖。在函數返回的結果中,有一個參數out,它是由異常值組成的列表。更準確的說函數列出了箱線圖中箱須線外的數據點,其中參數coef能夠控制箱須線從箱線盒上延伸出來的長度。

    b、使用LOF(局部異常因子)檢查異常值

    (1)LOF(局部異常因子)是一種基於密度識別異常值的算法,算法實現是:將一個點的局部密度與分佈在它周圍的點的密度想比較,若是前者明顯的比後者小,那麼這個點相對於周圍的點來講就處於一個相對比較稀疏的區域,這就代表該點是一個異常值。

    (2)LOF算法的缺點是它只是對數值型有效。包‘DMwR’、‘dprep’中lofactor()能夠計算LOF算法中的局部異常因子

    c、聚類檢測異常值

    先把數據聚成不一樣的類,選擇不屬於任何類的數據做爲異常值,如:

    (1)基於密度的聚類DBSCAN算法的實現就是將數據稠密區域緊密相連的數據對象劃分爲一個類,所以與其餘對象分離的數據就做爲異常值。

    (2)也可使用K均值算法實現異常的檢測。首先經過把數據劃分爲k組,劃分分析是選擇距離各自簇中心最近的點爲一組,而後計算每一個對象和對應的簇中心距離(或者類似度),並挑出擁有最大的距離的點做爲異常值

 

    對X2變量age進行定量分享分析,發現有年齡爲0,因此須要刪除

> unique(traindata1$x2) #發現年齡有0值,因此須要刪除
 [1]  45  40  38  30  49  74  57  39  27  51  46  76  64  78  53  43  25  32  58  50  69  24  28  62  42  75  26  52
[29]  41  81  31  68  70  73  29  55  35  72  60  67  36  56  37  66  83  34  44  48  61  80  47  59  77  63  54  33
[57]  79  65  86  92  23  87  71  22  90  97  84  82  91  89  85  88  21  93  96  99  94  95 101  98 103 102 107 105
[85]   0 109
> traindata1 <-  traindata[-which(traindata1$x2 == 0),]

    對於x3,x7,x9三個變量,經過下面箱線圖,看看出,存在異常值,由nuique()函數能夠看到異常值9八、96,進行刪除

> unique(traindata1$x3)
 [1]  2  0  1  3  4  5  7 10  6 98 12  8  9 96 13 11
> unique(traindata1$x7)
 [1]  0  1  3  2  5  4 98 10  9  6  7  8 15 96 11 13 14 17 12
> unique(traindata1$x9)
 [1]  0  1  2  5  3 98  4  6  7  8 96 11  9

#能夠將x3,x7,x9取來繪製箱線圖
boxplot(traindata1[,c('x3','x7','x9')])

#去掉異常值96和98
#由於有96和98值的x三、x七、x9是在同一行,因此動一個變量便可
traindata1 <-  traindata1[-which(traindata1$x3 == 96),]

 

其餘的變量暫時不作處理

  • 3、單變量分析

    一、單變量分析

    能夠簡單的看下部分變量的分佈,好比對於age變量,以下圖

> library(ggplot2)
> ggplot(traindata, aes(x = x2, y = ..density..)) + geom_histogram(fill = "blue", colour = "grey60", size = 0.2, alpha = 0.2) + geom_density()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

    能夠看到年齡變量大體呈正態分佈,符合統計分析的假設,再好比月收入變量,也能夠作圖觀察

> ggplot(traindata, aes(x = x5,y = ..density..)) + 
+       geom_histogram(fill = "blue", colour = "grey60", size = 0.2, alpha = 0.2) + 
+       geom_density() + 
+       xlim(1, 20000)
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning messages:
1: Removed 18193 rows containing non-finite values (stat_bin). 
2: Removed 18193 rows containing non-finite values (stat_density). 
3: Removed 1 rows containing missing values (geom_bar).

    也收入也大體符合正態分佈,符合統計分析的須要

 

     二、變量之間的相關性

建模之間首先要檢驗變量之間的相關性,若是變量之間相關性顯著,會影響到模型的預測效果。下面經過corrplot函數,包括響應變量與自變量的相關性

cor1 <- cor(traindata[,1:11])
library(corrplot)
corrplot(cor1)  #以下圖

 

> corrplot(cor1,method = 'number') #用數字顯示

 

由上圖能夠看出,各變量之間的相關性是很是小的。其實Logistic迴歸一樣須要多重共線性問題,可是變量相關性很小,初步判斷不存在多重共線性問題,在建模以後用VIF(方差膨脹因子)來檢驗多重共線性問題,若是存在多重共線性問題,須要將變量降維或剔除處理

 

  • 4、切分數據集
> table(traindata1$y)

     0      1 
139851   9879

由上表看出,對於響應變量SeriousDlqin2yrs,存在明顯的失衡問題, SeriousDlqin2yrs等於1的觀測爲9879,僅爲全部觀測值的6.6%。所以須要對非平衡數據進行處理,能夠採用 SMOTE算法 ,用R對稀有事件進行超級採樣

利用caret包中的createDataPartition(數據分割功能)函數將數據隨機分紅相同的兩份

> library(caret)
> set.seed(1234)
> splitIndex <- createDataPartition(traindata1$y,time=1,p=0.5,list=F) #使用createDataPartition劃分數據
> train <- traindata1[splitIndex,]#訓練集
> test <- traindata1[-splitIndex,] #測試集
> prop.table(table(train$y)) #每類佔整體的比重

         0          1 
0.93314633 0.06685367 
> prop.table(table(test$y))

         0          1 
0.93489615 0.06510385

    訓練集和測集的結果是平衡的,大體都爲6.6%左右,所以能夠採用這份切割的數據進行建模及預測。

  • 5、Logistic迴歸

Logistic迴歸在信用評分卡開發中起到核心做用。因爲其特色,以及對自變量進行了權重轉換(WOE),logistic迴歸的結果能夠直接轉換爲一個彙總表,即所謂的標準評分卡格式

    一、基本公式

Logistic迴歸模型其自己是一個非線性迴歸模型,通過logit轉換(鏈接函數)將相應變量Y和線性自變量聯繫,能夠獲得一個線性形式,使用線性回顧模型對參數進行估計,因此說logistic迴歸模型是一個廣義線性迴歸模型

 

    二、創建模型

首先利用glm函數對全部變量進行 Logistic迴歸建模,模型以下

> fit <- glm(y~.,train,family='binomial')
> summary(fit)

Call:
glm(formula = y ~ ., family = "binomial", data = train)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-4.6144  -0.3399  -0.2772  -0.2240   3.6997  

Coefficients:
              Estimate Std. Error z value Pr(>|z|)    
(Intercept) -1.812e+00  6.411e-02 -28.268  < 2e-16 ***
x1          -1.846e-05  8.972e-05  -0.206 0.836948    
x2          -2.861e-02  1.276e-03 -22.428  < 2e-16 ***
x3           5.767e-01  1.564e-02  36.867  < 2e-16 ***
x4          -2.321e-05  1.538e-05  -1.509 0.131224    
x5          -1.355e-05  3.845e-06  -3.524 0.000425 ***
x6          -2.769e-03  3.798e-03  -0.729 0.466051    
x7           8.468e-01  2.429e-02  34.855  < 2e-16 ***
x8           8.620e-02  1.599e-02   5.393 6.94e-08 ***
x9           8.294e-01  3.338e-02  24.848  < 2e-16 ***
x10          5.126e-02  1.388e-02   3.694 0.000221 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 36747  on 74864  degrees of freedom
Residual deviance: 29793  on 74854  degrees of freedom
AIC: 29815

Number of Fisher Scoring iterations: 6

    能夠看出利用全變量進行迴歸,模型擬合效果並不很好,其中x1,x4,x6三 個變量的p值不顯著,未能經過檢驗,在此直接將其刪除,在利用剩餘的變量對y進行迴歸

> fit2<-glm(y~x2+x3+x5+x7+x8+x9+x10,train,family = "binomial")
> summary(fit2)

Call:
glm(formula = y ~ x2 + x3 + x5 + x7 + x8 + x9 + x10, family = "binomial", 
    data = train)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-4.6223  -0.3402  -0.2777  -0.2239   3.5868  

Coefficients:
              Estimate Std. Error z value Pr(>|z|)    
(Intercept) -1.825e+00  6.320e-02 -28.873  < 2e-16 ***
x2          -2.894e-02  1.252e-03 -23.120  < 2e-16 ***
x3           5.742e-01  1.544e-02  37.187  < 2e-16 ***
x5          -1.185e-05  3.513e-06  -3.373 0.000744 ***
x7           8.500e-01  2.401e-02  35.397  < 2e-16 ***
x8           7.494e-02  1.420e-02   5.276 1.32e-07 ***
x9           8.306e-01  3.338e-02  24.883  < 2e-16 ***
x10          5.169e-02  1.386e-02   3.730 0.000192 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 36747  on 74864  degrees of freedom
Residual deviance: 29797  on 74857  degrees of freedom
AIC: 29813

Number of Fisher Scoring iterations: 6

    第二個迴歸模型全部變量都經過了檢驗,甚至AIC值(赤池信息準則)更小,全部模型的擬合效果更好些。

 

    三、模型評估

    一般一個二值分類器能夠經過ROC(Receiver Operating Chatacteristic)曲線和AUC值來評價優劣。

    混淆矩陣    

    不少二元分類器可會產生一個機率預測值,而非僅僅是0-1預測值。可使用某個臨界點(例如0.5),以劃分哪些預測爲1,哪些預測爲0。獲得二元預測後,能夠構建一個混淆矩陣來評價二元分類器的預測效果。

    全部的訓練數據都會落入這矩陣中,而對角線上的數字表明瞭預測正確的數目,即ttue positive + ture nagetive。同時能夠相應算出TPR(真正率或稱爲靈敏度)和TNR(真負率或稱爲特異度)。咱們主觀上但願這兩個指標越大越好,但惋惜兩者是此消彼漲的關係,除了分類器的訓練參數,臨界點的選擇也會大大的影響TPR和TNR。有時能夠根據具體問題和須要,來選擇具體的臨界點

[參考]分類模型的評估方法

技術分享

 

    ROC曲線

    若是咱們選擇一系列的臨界點,就會獲得一系列的TPR和TNR,將這些值對應的點鏈接起來,就構成了ROC曲線。ROC曲線能夠幫助咱們清楚的瞭解到這個分類器的性能表現,還能方便比較不一樣分類器的性能。在繪製ROC曲線的時候,習慣上使用1-TNR做爲橫座標即FPR(false positive rate),TRP做爲縱座標。這是造成了ROC曲線

 

     AUC(Area Under Curve)

被定義ROC曲線下的面積,顯然這個面積的數值不會大於1,又因爲ROC曲線通常都處於y=x這條直線的上方,因此AUC的取值範圍在0.5-1之間。使用AUC值做爲評價標準是由於不少時候ROC曲線並不能清晰的說明哪一個分類器效果更好,而做爲一個數值,對應AUC更大的分類器效果更好

    下面首先利用模型對test數據進行預測,生成機率預測值

pre <- predict(fit2,test)

    在R中,能夠利用pROC包,它能方便比較兩個分類器,還能自動標註出最優的臨界點,圖看起來比較 漂亮,在下圖中最優勢FPR =1-TNR=0.845,TPR=0.638,AUC值爲0.8102,說明該模型的預測效果仍是不錯的,正確較高

> library(pROC)
There were 50 or more warnings (use warnings() to see the first 50)
> modelroc <- roc(test$y,pre)
> plot(modelroc,print.auc=T,auc.ploygon=T,grid=c(0.1,0.2),
+      grid.col=c('green','red'),max.auc.polygon=T,
+      auc.ploygon.col='skyblue',
+      print.thres=T)

Call:
roc.default(response = test$y, predictor = pre)

Data: pre in 69991 controls (test$y 0) < 4874 cases (test$y 1).
Area under the curve: 0.8102

  • 6、WOE轉換

    證據權重(Weight of Evidence,WOE)轉換能夠將Logistic迴歸模型轉變爲標準評分卡格式。引入WOE轉換的目的並非爲了提升模型質量,只是一些變量不該該被歸入模型,這或者是由於他們不能增長模型值,或者是由於與其模型相關係數有關的偏差較大,其實創建標準信用評分卡也能夠不採用WOE轉換。這種狀況下,Logistic迴歸模型須要處理更大數量的自變量。儘管這樣會增長建模程序的複雜性,但最終獲得的評分卡都是同樣。

    用WOE(x)替換變量x,WOE()= ln[(違約/總違約)/(正常/總正常)]

    經過上述的Logistic迴歸,剔除x1,x4,x6三個變量,對剩下的變量進行WOE轉換

    1 、進行分箱

    計算WOE的值須要將連續性變量離散化,因此須要對age變量(x2)進行分箱操做

> cutx2= c(-Inf,30,35,40,45,50,55,60,65,75,Inf)  #定義分箱的邊界,
There were 50 or more warnings (use warnings() to see the first 50)
> plot(cut(train$x2,cutx2))  # 對數據進行分箱,Inf表示函數的下界,注意是默認是左開右閉

 

    NumberOfTime30-59DaysPastDueNotWorse變量(x3)也進行分箱

> cutx3 = c(-Inf,0,1,3,5,Inf)
> plot(cut(train$x3,cutx3))

    MonthlyIncome變量(x5)進行分箱:

> cutx5 = c(-Inf,1000,2000,3000,4000,5000,6000,7500,9500,12000,Inf)
> plot(cut(train$x5,cutx5))

技術分享

    NumberOfTimes90DaysLate變量(x7)

> cutx7 = c(-Inf,0,1,3,5,10,Inf)
> plot(cut(train$x7,cutx7))

     NumberRealEstateLoansOrLines變量(x8):

> cutx8= c(-Inf,0,1,2,3,5,Inf)
> plot(cut(train$x8,cutx8))

 

    NumberOfTime60-89DaysPastDueNotWorse變量(x9):

> cutx9 = c(-Inf,0,1,3,5,Inf)
> plot(cut(train$x9,cutx9))

2

 

     NumberOfDependents變量(x10):

> cutx10 = c(-Inf,0,1,2,3,5,Inf)
> plot(cut(train$x10,cutx10))

    二、計算WOE值

    計算WOE的函數

> totalgood = as.numeric(table(train$y))[1]    #table(train$y)獲取y中的分類,table(train$y)[1]取出第1類表示未違約的數
> totalbad = as.numeric(table(train$y))[2]     #取出違約數
> getWOE <- function(a,p,q){
+   Good <- as.numeric(table(train$y[a > p & a <= q]))[1]
+   Bad <- as.numeric(table(train$y[a > p & a <= q]))[2]
+   WOE <- log((Bad/totalbad)/(Good/totalgood),base = exp(1))
+   return(WOE)
+   
+ }



#計算出分箱後年齡的WOE
> Agelessthan30.WOE=getWOE(train$x2,-Inf,30)
    #分析function()的過程
    #分析下上述function,以getWOE(train$x2,-Inf,30)爲例
    #train$y  獲取訓練集中的 1(違約) 和 0(不違約)的數目
    #table(train$y[train$x2 > -Inf & train$x2 <= 30 ])  知足x2(age變量)從-Inf < x2(年齡變量) <= 30 的1,0的數目
    #Good <- as.numeric(table(train$y[train$x2 > -Inf & train$x2 <= 30 ]))[1]  取出違約的  
    #一樣的計算Bad,而後帶入WOE公式,計算出 分箱(-Inf,30]這組的WOE值
    
> Age30to35.WOE=getWOE(train$x2,30,35)
> Age35to40.WOE=getWOE(train$x2,35,40)
> Age40to45.WOE=getWOE(train$x2,40,45)
> Age45to50.WOE=getWOE(train$x2,45,50)
> Age50to55.WOE=getWOE(train$x2,50,55)
> Age55to60.WOE=getWOE(train$x2,55,60)
> Age60to65.WOE=getWOE(train$x2,60,65)
> Age65to75.WOE=getWOE(train$x2,65,75)
> Agemorethan.WOE=getWOE(train$x2,75,Inf)
    
> age.WOE=c(Agelessthan30.WOE,Age30to35.WOE,Age35to40.WOE,Age40to45.WOE,Age45to50.WOE,
+           Age50to55.WOE,Age55to60.WOE,Age60to65.WOE,Age65to75.WOE,Agemorethan.WOE)
> age.WOE
 [1]  0.57432879  0.52063157  0.34283924  0.24251193  0.22039521  0.07194294 -0.25643603 -0.55868003 -0.94144504
[10] -1.28914527

 其餘的也相似計算出WOE的值, NumberOfTime30-59DaysPastDueNotWorse變量(x3)

[1] -0.5324915  0.9106018  1.7645290  2.4432903  2.5682332

    MonthlyIncome變量(x5)    

[1] -1.128862326  0.448960482  0.312423080  0.350846777  0.247782295
[6]  0.114417168 -0.001808106 -0.237224039 -0.389158800 -0.462438653

    NumberOfTimes90DaysLate變量(x7)

[1] -0.3694044  1.9400973  2.7294448  3.3090003  3.3852925  2.3483738

    NumberRealEstateLoansOrLines變量(x8)

[1]  0.21490691 -0.24386987 -0.15568385  0.02906876  0.41685234  1.12192809

  NumberOfTime60-89DaysPastDueNotWorse變量(x9)

[1] -0.2784605  1.8329078  2.7775343  3.5805174  3.4469860

    NumberOfDependents變量(x10)

[1] -0.15525081  0.08669961  0.19618098  0.33162486  0.40469824  0.76425365

 

    三、對變量進行WOE變換

    如age變量(x2)

> tmp.age <- 0
> for(i in 1:nrow(train)) {
+   if(train$x2[i] <= 30)
+     tmp.age[i] <- Agelessthan30.WOE
+   else if(train$x2[i] <= 35)
+     tmp.age[i] <- Age30to35.WOE
+   else if(train$x2[i] <= 40)
+     tmp.age[i] <- Age35to40.WOE
+   else if(train$x2[i] <= 45)
+     tmp.age[i] <- Age40to45.WOE
+   else if(train$x2[i] <= 50)
+     tmp.age[i] <- Age45to50.WOE
+   else if(train$x2[i] <= 55)
+     tmp.age[i] <- Age50to55.WOE
+   else if(train$x2[i] <= 60)
+     tmp.age[i] <- Age55to60.WOE
+   else if(train$x2[i] <= 65)
+     tmp.age[i] <- Age60to65.WOE
+   else if(train$x2[i] <= 75)
+     tmp.age[i] <- Age65to75.WOE
+   else
+     tmp.age[i] <- Agemorethan.WOE
+ }
> table(tmp.age)
tmp.age
  -1.2891452711972 -0.941445039519045 -0.558680027962495 -0.256436029353835 0.0719429392949312  0.220395209955515 
              5063               9196               8180               8472               9009               9465 
 0.242511934081286  0.342839240194068   0.52063156705216  0.574328792863984 
              8008               6784               5390               5298 
    
 > tmp.age[1:10]
 [1] 0.34283924 0.57432879 0.34283924 0.57432879 0.07194294 0.22039521 0.07194294 0.24251193 0.34283924 0.52063157

    一樣的分別對其餘的變量進行轉換,NumberOfTime30-59DaysPastDueNotWorse變量(x3)

tmp.NumberOfTime30.59DaysPastDueNotWorse
-0.53249146131578 0.910601840444591  1.76452904024992  2.44329031065646 
            62948              8077              3160               562 
 2.56823323027274 
               118

[1]  0.9106018 -0.5324915 -0.5324915 -0.5324915 -0.5324915 -0.5324915
[7] -0.5324915 -0.5324915 -0.5324915 -0.5324915
[1] 1 0 0 0 0 0 0 0 0 0

    MonthIncome變量(x5)

tmp.MonthlyIncome
    -1.12886232582259   -0.462438653207328   -0.389158799506996 
                10201                 5490                 5486 
   -0.237224038650003 -0.00180810632297072    0.114417167554772 
                 7048                 8076                 7249 
    0.247782294610166    0.312423079500641    0.350846777249291 
                 9147                 8118                 9680 
    0.448960482499888 
                 4370
  [1]  0.350846777  0.350846777  0.350846777  0.312423080 -0.001808106
  [6] -0.462438653 -0.237224039  0.350846777  0.312423080 -0.237224039
  [1]  3042  3300  3500  2500  6501 12454  8800  3280  2500  7916

    NumberOfTime90DaysPastDueNotWorse變量(x7)

tmp.NumberOfTimes90DaysLate
 -0.369404425455224   1.94009728631401   2.34837375415972 
              70793               2669                  7 
   2.72944477623793   3.30900029985393   3.38529247382249 
               1093                222                 81
  [1]  1.9400973 -0.3694044 -0.3694044 -0.3694044 -0.3694044 -0.3694044
  [7] -0.3694044 -0.3694044 -0.3694044 -0.3694044
  [1] 1 0 0 0 0 0 0 0 0 0

    NumberRealEstateLoansOrLines變量(x8)

tmp.NumberRealEstateLoansOrLines
 -0.243869874062293 -0.155683851792327 0.0290687559545721 
              26150              15890               3130 
  0.214906905417014   1.12192809398173 
              27901               1794
  [1]  0.2149069  0.2149069  0.2149069  0.2149069 -0.1556839 -0.1556839
  [7]  0.2149069 -0.2438699  0.2149069  0.2149069
  [1] 0 0 0 0 2 2 0 1 0 0

    NumberOfTime60.89DaysPastDueNotWorse變量(x9)

tmp.NumberOfTime60.89DaysPastDueNotWorse
 -0.278460464730538   1.83290775083723   2.77753428092856 
              71150               2919                708 
   3.44698604282783   3.58051743545235 
                 13                 75
  [1] -0.2784605 -0.2784605 -0.2784605 -0.2784605 -0.2784605 -0.2784605
  [7] -0.2784605 -0.2784605 -0.2784605 -0.2784605
  [1] 0 0 0 0 0 0 0 0 0 0

     NumberOfDependents變量(x10)

tmp.NumberOfDependents
 -0.155250809857344 0.0866996065110081  0.196180980387687 
              43498              14544              10102 
  0.331624863227172  0.404698242905824   0.76425364970991 
               4771               1815                135
  [1] -0.1552508 -0.1552508 -0.1552508 -0.1552508  0.1961810  0.1961810
  [7] -0.1552508  0.1961810 -0.1552508 -0.1552508
  [1] 0 0 0 0 2 2 0 2 0 0

    四、WOE DataFrame構建:

trainWOE =cbind.data.frame(tmp.age,tmp.NumberOfTime30.59DaysPastDueNotWorse,tmp.MonthlyIncome,tmp.NumberOfTime60.89DaysPastDueNotWorse,tmp.NumberOfTimes90DaysLate,tmp.NumberRealEstateLoansOrLines,tmp.NumberOfDependents)

 

  • 7、評分卡的建立和實施

    標準評分卡採用的格式是評分卡中的每個變量都遵循一系列IF-THEN法則,變量的值決定了該變量所分配的分值,總分就是各變量分值的和

技術分享

知道線性表達式的兩個參數A,B後就能夠求每條記錄(申請人)的分值。爲了求得A,B,須要設定兩個假設(分數的給定,很主觀)。以上就是推斷,實際代碼中,習慣用了q、p來表明A、B.通俗來講就是,評分須要本身預設一個閥值,好比:

 

    這我的預測出來「不發生違約」的概率爲0.8,設定這我的爲500分;

 

    另外一我的預測出來「不發生違約」的概率爲0.9,設定這我的爲600分。

 

    閥值的設定需根據行業經驗不斷跟蹤調整,下面的分數設定僅表明我的經驗。

  下面開始設立評分,假設按好壞比15爲600分,每高20分好壞比翻一倍算出P,Q。若是後期結果不明顯,能夠高30-50分好壞比才翻一倍。

    Score = q - p * log(odds)

  即有方程:

    620 = q - p * log(15)

    600 = q - p * log(15/2)

    邏輯迴歸建模

#由於數據中「1」表明的是違約,直接建模預測,求的是「發生違約的機率」,log(odds)即爲「壞比如」。爲了符合常規理解,分數越高,信用越好,全部就調換「0」和「1」,使建模預測結果爲「不發生違約的機率」,最後log(odds)即表示爲「好壞比」。
trainWOE$y = 1-train$y
glm.fit = glm(y~.,data = trainWOE,family = binomial(link = logit))
summary(glm.fit)
coe = (glm.fit$coefficients)
p <- 20/log(2)
q <- 600-20*log(15)/log(2)
Score=q + p*{as.numeric(coe[1])+as.numeric(coe[2])*tmp.age +as.numeric(coe[3])*tmp.NumberOfTime30.59DaysPastDueNotWorse+p*as.numeric(coe[4])*tmp.MonthlyIncome+p*as.numeric(coe[5])*tmp.NumberOfTime60.89DaysPastDueNotWorse+p*as.numeric(coe[6])*tmp.NumberOfTimes90DaysLate+p*as.numeric(coe[7])*tmp.NumberRealEstateLoansOrLines+p*as.numeric(coe[8])*tmp.NumberOfDependents

    我的總評分=基礎分+各部分得分

    基礎分爲:

base <- q + p*as.numeric(coe[1])
base
## [1] 446.2841

 

    一、對各變量進行打分

好比age變量(x2)

Agelessthan30.SCORE = p*as.numeric(coe[2])*Agelessthan30.WOE
Age30to35.SCORE = p*as.numeric(coe[2])*Age30to35.WOE
Age35to40.SCORE = p*as.numeric(coe[2])*Age35to40.WOE
Age40to45.SCORE = p*as.numeric(coe[2])*Age40to45.WOE
Age45to50.SCORE = p*as.numeric(coe[2])*Age45to50.WOE
Age50to55.SCORE = p*as.numeric(coe[2])*Age50to55.WOE
Age55to60.SCORE = p*as.numeric(coe[2])*Age55to60.WOE
Age60to65.SCORE = p*as.numeric(coe[2])*Age60to65.WOE
Age65to75.SCORE = p*as.numeric(coe[2])*Age65to75.WOE
Agemorethan.SCORE=p*as.numeric(coe[2])*Agemorethan.WOE
Age.SCORE =c(Age30to35.SCORE,Age35to40.SCORE,Age40to45.SCORE,Age45to50.SCORE,Age50to55.SCORE,Age55to60.SCORE,Age60to65.SCORE,Age65to75.SCORE,Agemorethan.SCORE)
Age.SCORE
## [1]  10.498828   6.913546   4.890389   4.444393   1.450770  -5.171176
## [7] -11.266096 -18.984767 -25.996338

    NumberOfTime30-59DaysPastDueNotWorse變量(x3)

## [1] -10.29843  17.61112  34.12614  47.25344  49.66985

    MonthlyIncome變量(x5)

##  [1] -24.92797904   9.91412083   6.89904854   7.74753565   5.47162546
##  [6]   2.52660461  -0.03992731  -5.23847393  -8.59355669 -10.21175106

    NumberOfTimes90DaysLate變量(x7)

## [1] -5.19482 27.28299 38.38333 46.53344 47.60632 33.02445

    NumberRealEstateLoansOrLine變量(x8)

## [1]  4.022310 -4.564396 -2.913860  0.544066  7.802025 20.998590

    NumberOfTime60-89DaysPastDueNotWorse變量(x9)

## [1] -4.820833 31.732126 48.085927 61.987533 59.675778

    NumberOfDependents變量(x10)

## [1] -1.5734012  0.8786638  1.9882112  3.3608775  4.1014453  7.745387

 構造計算分值函數

getscore<-function(i,x){
  score = round(p*as.numeric(coe[i])*x,0)
  return(score)
}

 二、計算各變量分箱得分:

     age變量(x2)

Agelessthan30.SCORE = getscore(2,Agelessthan30.WOE)
Age30to35.SCORE = getscore(2,Age30to35.WOE)
Age35to40.SCORE = getscore(2,Age35to40.WOE)
Age40to45.SCORE = getscore(2,Age40to45.WOE)
Age45to50.SCORE = getscore(2,Age45to50.WOE)
Age50to55.SCORE = getscore(2,Age50to55.WOE)
Age55to60.SCORE = getscore(2,Age55to60.WOE)
Age60to65.SCORE = getscore(2,Age60to65.WOE)
Age65to75.SCORE = getscore(2,Age65to75.WOE)
Agemorethan.SCORE = getscore(2,Agemorethan.WOE)
Age.SCORE = c(Agelessthan30.SCORE,Age30to35.SCORE,Age35to40.SCORE,Age40to45.SCORE,Age45to50.SCORE,Age50to55.SCORE,Age55to60.SCORE,Age60to65.SCORE,Age65to75.SCORE,Agemorethan.SCORE)
Age.SCORE
##  [1]  12  10   7   5   4   1  -5 -11 -19 -26

    NumberOfTime30-59DaysPastDueNotWorse變量(x3)

## [1] -10  18  34  47  50

    MonthlyIncome變量(x5)

##  [1] -25  10   7   8   5   3   0   0  -9 -10

    NumberOfTimes90DaysLate變量(x7)

## [1] -5 27 38 47 48 33

    NumberRealEstateLoansOrLine變量(x8)

## [1]  4 -5 -3  1  8 21

    NumberOfTime60-89DaysPastDueNotWorse變量(x9)

## [1] -5 32 48 62 60

    NumberOfDependents變量(x10)

## [1] -2  1  2  3  4  8

 

    三、最終生成的評分卡以下:

age X2 <=30 (30,35] (35,40] (40,45] (45,50] (50,55] (55,60] (60,65] (65,75] (75,100]
Score 12 10 7 5 4 1 -5 -11 -19 -26
NumberOfTime30-59DaysPastDueNotWorse X3 <=0 (0,1] (1,3] (3,5] >5
Score -10 18 34 47 50
MonthlyIncome X5 <=1000 (1000,2000] (2000,3000] (3000,4000] (4000,5000] (5000,6000] (6000,7500] (7500,9500] (9500,12000] >12000
Score -25 10 7 8 6 3 0 0 -9 -10
NumberOfTimes90DaysLate X7 <=0 (0,1] (1,3] (3,5] (5,10] >10
Score -5 27 38 47 48 33
NumberRealEstateLoansOrLines X8 <=0 (0,1] (1,2] (2,3] (3,5] >5
Score 4 -5 -3 1 8 21
NumberOfTime60-89DaysPastDueNotWorse X9 <=0 (0,1] (1,3] (3,5] >5
Score -5 32 48 62 60
NumberOfDependents X10 <=0 (0,1] (1,2] (2,3] (3,5] >5
Score -2 1 2 3 4 8

 

特徵 數據 分數
Age 38 7
NumberOfTime30-59DaysPastDueNotWorse 4 47
MonthlyIncome 1500 10
NumberOfTimes90DaysLate 2 38
NumberRealEstateLoansOrLines 1.5 -3
NumberOfTime60-89DaysPastDueNotWorse 4 62
NumberOfDependents 1.5 2

 

  • 我的評分計算案例

  因此這我的的總評分 = 基礎分(base)+ 各特徵分數

  總評分 = 446.2841+7+47+10+38-3+62+2 = 609.2841

相關文章
相關標籤/搜索