生產環境下的信用評分卡實踐(R語言)
前段時間折騰了一個個人博客,以後那邊應該會是寫文章的主要陣地,這邊放個鏈接吧,有問題可以留言討論。
原文鏈接:生產環境下的信用評分卡實踐(R語言)
搬運過來如下:
入職將近兩個月,在領導和同事的關心和幫助下,基本上順利地完成了角色轉變,平穩地度過了過度期:從一個火力發電廠熱力系統設計工程師以及能源項目規劃師以及海外電站項目開發經理華麗轉身為互聯網金融風控業務的數據挖掘工程師。
在這段時間當中,主要的工作內容就是根據公司目前積累的數據以及從第三方平台接入的數據構建用戶信用評分卡,包括申請評分和行為評分,以下結合本人主要參與的行為評分卡建模,分享一些這段時間遇到的一些問題以及對應的解決方案。
Mac系統下R的安裝和配置
工欲善其事,必先利其器,首先要將R以及RStudio在Mac系統上面安裝並配置好。
R的安裝
Mac系統下安裝有很多種方法,可以使用HomeBrew進行安裝。
HomeBrew是Mac系統下的一個包管理工具,類似Debian系統下的apt-get命令,不過通常不是默認安裝的,需要用以下命令進行安裝:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
然後安裝R的命令如下:
brew install R
另外也可以直接去R的官方網站直接下載安裝包進行安裝,並且同步安裝GUI工具,雖然比較雞肋。針對Mac系統主要相關的下載及文檔如下:
- R安裝包:R for Mac OS X
- R for Mac-FAQ: R Mac OS X-FAQ
- 畫圖所需要的xquartz軟體包:Xquartz
R的配置--替換BLAS庫
參考替換R自帶的BLAS庫來加速的描述:
矩陣運算是科學計算(包括統計)中最重要的組成部分,而科學計算軟體包(R/Matlab/Numpy/Julia等)的矩陣運算都是通過調用經過BLAS庫(Basic Linear Algebra Subprograms)來實現的,所以一個好的BLAS庫自然對於加速科學計算有著根本性的作用。現在公認最好的BLAS庫是Intel公司的MKL,收費很高;而開源世界中的OpenBLAS基本能達到MKL的速度;另外就是OS X自帶的Accelerate framework對於Mac用戶來說簡直就是一大福音,讓我們不用再費腦筋去自己編譯OpenBLAS。
為了提高R的運算速度,非常有必要將替換默認的BLAS庫。
首先進入到R自帶的BLAS庫的所在文件夾
cd /Library/Frameworks/R.framework/Resources/lib
找到文件libRblas.dylib,它是一個symlink,默認指向同文件夾中的libRblas.0.dylib,這個就是R自帶的BLAS庫文件了。我們現在需要做的就是把這個symlink文件指向其他的BLAS庫文件(Accelerate framework或者OpenBLAS):
## 指向Accelerate frameworkln -sf /System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/Versions/Current/libBLAS.dylib libRblas.dylib## 指向OpenBLAS### 添加homebrew科學庫brew tap homebrew/science## 使用brew 安裝openblas包brew install openblascd /Library/Frameworks/R.framework/Resources/lib## openblas具體安裝路徑會隨著版本略有不同ln -sf /usr/local/Cellar/openblas/0.2.20_1//lib/libopenblas.dylib libRblas.dylib
R包的安裝
R包的安裝在Mac系統下面通常有三種方法:
- 最常規的方法就是在R的console窗口下面調用install.packages()命令,比如要安裝ggplot2包則命令如下:
> install.packages("ggplot2")trying URL https://mirrors.ustc.edu.cn/CRAN/bin/macosx/el-capitan/contrib/3.4/ggplot2_2.2.1.tgzContent type application/octet-stream length 2792414 bytes (2.7 MB)==================================================downloaded 2.7 MBThe downloaded binary packages are in /var/folders/t0/csmkjx2s3cn0dgsd2t4zmf_w0000gn/T//RtmpTVfycx/downloaded_packages>
install.packages()命令會默認從你設定好的CRAN鏡像地址下載已經被收錄的包,比如上面The Comprehensive R Archive Network就是我設定的鏡像地址。
- 在實際的工作中,也許我們還會用到還沒有被CRAN收入的包,比如來自Github的包,這就需要用到devtools包了,devtools包提供了從CRAN以外安裝R的工作命令,以下以構建評分卡中關鍵的分箱步驟所需要用到的WOE包為例演示下devtools包的使用方法。
#首先需要安裝載入devtools包> install.packages("devtools")trying URL https://mirrors.ustc.edu.cn/CRAN/bin/macosx/el-capitan/contrib/3.4/devtools_1.13.5.tgzContent type application/octet-stream length 439289 bytes (428 KB)==================================================downloaded 428 KBThe downloaded binary packages are in /var/folders/t0/csmkjx2s3cn0dgsd2t4zmf_w0000gn/T//RtmpTVfycx/downloaded_packages> library(devtools)> install_github(repo="riv",username="tomasgreif") Downloading GitHub repo tomasgreif/riv@masterfrom URL https://api.github.com/repos/tomasgreif/riv/zipball/masterInstalling woe/Library/Frameworks/R.framework/Resources/bin/R --no-site-file --no-environ --no-save --no-restore --quiet CMD INSTALL /private/var/folders/t0/csmkjx2s3cn0dgsd2t4zmf_w0000gn/T/RtmpTVfycx/devtoolsae3d6bf947d/tomasgreif-woe-43fcf26 --library=/Library/Frameworks/R.framework/Versions/3.4/Resources/library --install-tests * installing *source* package 『woe』 ...** R** data*** moving datasets to lazyload DB** demo** preparing package for lazy loading** help*** installing help indices** building package indices** testing if installed package can be loaded* DONE (woe)Warning message:Username parameter is deprecated. Please use tomasgreif/riv > library(woe)>
- 在Mac系統下面還有一種在命令行下面直接從源代碼安裝的方法,首先從CRAN下載打包後的源代碼,比如你要安裝foo_0.1.tar.gz包,可以用以下命令:
R CMD INSTALL foo_0.1.tar.gz
RStudio的安裝
RStudio作為一個IDE,極大地增加使用R的便利性,直接去官網下載免費版本即可,RStudio可以自動識別系統已經安裝的R。
數據抽取
巧婦難為無米之炊,數據是源頭。通常數據都保存在結構化資料庫當中,並且以MySQL居多,這就要求有一定的SQL代碼能力。會寫簡單的子查詢並會跨表查詢併合並。
行為評分當中最關鍵也是在我實踐過程當中出現問題最多次的是對Y值的定義邏輯,以及如何把這個邏輯轉化為SQL代碼並將數據準確無誤地取出來。正確地定義並獲得Y也是後面數據清洗、轉化、特徵工程、建模等工作的基礎,如果Y都定義不對,後面模型建的再漂亮都是徒勞的。
下面這張圖主要是想說明行為評分當中用戶行為數據的統計時間段。從行為評分的目的來看,我們是想根據用戶以往的行為數據以及實際的逾期情況來預測用戶未來的逾期概率,但是這裡有一個問題,因為未來還沒有到來,實際上我們無法將還未發生的事情來放到模型裡面去進行訓練,也就是說,在當前的時間點來看,在訓練模型之前,我們無法知道用戶是否會逾期,因此,我們在訓練模型的時候只能使用已經發生並且確定的事情,這裡有一個小技巧,通常將截止當前時間節點的最後一筆訂單逾期情況作為訓練模型的Y,然後用倒數第二筆訂單之前的所有用戶行為統計情況作為自變數,最後得到可以用來預測未來用戶逾期情況的模型,示意圖如下:
需要特別注意的是:在統計用戶行為數據的時候的當前時間點是倒數第二筆訂單的還款時間,不要牽扯到最後一筆訂單相關的任何情況,不要牽扯到最後一筆訂單相關的任何情況,不要牽扯到最後一筆訂單相關的任何情況,重要的事情說三遍!否則會使你的某些因變數的IV值高得異常,模型也就失去意義。
邏輯上很好理解,因為對於最後一筆訂單的任何情況,在倒數第二筆訂單還款時間這個節點上都是未知的,如果在統計用戶行為數據牽涉到了最後一筆訂單的情況,勢必會導致一種用已知去預測已知的情況,這種模型是無法使用的。
如果模型中待預測的最後一筆訂單無逾期為0的話,通常會把逾期天數達到一定數目以上的定為1。而這個逾期天數可能因人而已,傳統銀行業通常將90天以上定位1。比如這裡將逾期天數設為20天,為了減少模型的干擾,那些逾期了,但是逾期天數在20天以內的樣本將會被剔除。
這裡有個坑,就是在寫SQL代碼的時候在剔除逾期且逾期天數在20天以內的樣本時要特別注意那些曾經逾期過且逾期天數在20天以內,但是最後一筆訂單已還款的用戶樣本要保留。
數據清洗
數據清洗的主要目的是將從各個不同資料庫中取得的數據進行整合處理,並對特徵進行初步篩選,可分為以下主要步驟:
數據讀入
這裡強烈建議使用tidyverse包中的一些組件,假設因變數和自變數的數據文件名分別為data.csv
和default.csv
,則數據讀入代碼如下:
#默認文件存儲在項目根目錄當中data_df <- read_csv("data.csv", na = c("", "NA", "NULL", "未知"))default_df <- read_csv("default.csv", na = c("", "NA", "NULL", "未知"))#na = 這個參數可以自定義原數據當中需要在**R**中要以**NA**來表示的字元#數據合併df <- data_df %>% inner_join(default_df, by = "id")
缺失值處理
缺失值處理一般兩個原則,缺失值比例很高的變數直接剔除,缺失值比較低的進行插補,這裡用mice包,並採用cart方法。不過在此之前需要識別缺失值。
#識別缺失值#統計所有變數的缺失值temp <- sapply(df, function(x) sum(is.na(x)))#按照缺失率排序miss <- sort(temp, decreasing = T)#查看含有缺失值的變數概括miss[miss>0]summary(df[,names(miss)[miss>0]])#mice插補用mice包插補缺失值,採用分類回歸樹演算法 cartimp <- mice(df,met="cart",m=1)df_imp <- complete(imp)
分箱及降維
分箱是將連續的變數離散化,增加粒度,去除噪音,同時在評分卡模型當中用變數的WOE值來代替離散化後的各個經過分箱處理的原變數,這是一種傳統而有效的方法。按照分箱標準的不同可有等深分箱,等寬分箱,最優分箱,用戶自定義區間。前面已經安裝並載入了WOE包,採用最優分箱演算法,可以比較簡便地進行WOE和IV的計算,不過這個包已經多年沒有維護了,有一些bug,有興趣的可以到下面的地址查看源碼:
- tomasgreif/woe
另,WOE和IV的具體定義可以參考以下鏈接:
- 數據挖掘模型中的IV和WOE詳解
在載入WOE包以後IV計算代碼如下:
#計算各變數IV值並排序(在調用iv.mult()函數之前必須將行名排序)row.names(df_imp) <- 1:nrow(df_imp) #假設Y值的變數名為defaultIV <- iv.mult(df_imp, "default", TRUE)#剔除IV值在0.02以下的變數IVcols <- filter(IV, IV$InformationValue>0.02)[1]IVcols <- c("default", IVcols$Variable)#將待訓練樣本降維df_imp <- df_imp[,IVcols]
經過IV值的大小淘汰一部分對於因變數預測價值不大的變數,然後將降維後的數據進入隨機森林進一步篩選變數,隨機森林的代碼如下:
set.seed(4321)crf <- cforest(default~.,control = cforest_unbiased(mtry = 20, ntree = 500), data = df_imp)varimpt <- data.frame(varimp(crf))c <- as.data.frame(varimpt)
- mtry是指定節點中用於二叉樹的變數個數,默認情況下數據集變數個數的二次方根(分類模型)或三分之一(預測模型)。一般是需要進行人為的逐次挑選,確定最佳的m值;
- ntree是指定隨機森林所包含的決策樹數目,默認為500,通常在性能允許的情況下越大越好。
事實上,比較好的做法是先用隨機森林,再用IV,因為後者的演算法更具解釋下,更加可控。但是考慮到隨機森林的計算複雜性,一開始太多的維度並且樣本已經10萬以上,普通的PC機會有些吃不消。
邏輯回歸建模
邏輯回歸的主要模型理論請參考以下鏈接:
- 使用R語言開發評分卡模型
R的包非常豐富,建模本身還是相對簡單的,但是通常不是一蹴而就的,需要不斷地迭代、替換變數。需要從以下幾個方面進行考慮:
- 變數的WOE值最好是單調的,遞減要麼遞增,不宜有太大的波動性,另外用來解釋因變數的邏輯應該符合常理,舉個例子,在以往的行為當中逾期越多的人接下來的逾期概率應該是越大才對;
- 查看模型的VIF(方差膨脹因子,定義如下),兩兩之間存在多重共線性的變數僅保留一個,為了得到更好的效果,可以保留IV值較大的那個;
方差膨脹因子(Variance Inflation Factor,VIF):是指解釋變數之間存在多重共線性時的方差與不存在多重共線性時的方差之比。容忍度的倒數,VIF越大,顯示共線性越嚴重。經驗判斷方法表明:當0<VIF<10,不存在多重共線性;當10≤VIF<100,存在較強的多重共線性;當VIF≥100,存在嚴重多重共線性。
- 然後是檢驗變數的顯著性指標,就是p值;
- 最後將最終的變數控制在15個以內。
隨機森林以後的變數可能還有50~60個,這時候可以直接放到羅輯回歸當中建模,建模以後利用逐步回歸進一步篩選變數。核心代碼如下:
#邏輯回歸初步lg.full <- glm(default ~.,family = binomial(link=logit), data = train)#查看模型summary(lg.full)#逐步回歸lg_both <- step(lg.full, direction = "both")#查看逐步回歸後模型summary(lg_both)#查看vifvif(lg_both)#將vif結果保留write.csv(vif(lg_both), "vif.csv")
這裡再分享一個技巧,可以構造一個字元型的數組用來存儲最終進入模型的變數名,然後用這個數組變數來索引要進行訓練的變數。這樣有以下兩個好處:
- 首先是比較直觀地能夠知道哪些變數進入了模型,不管是你自己回過頭來看還是與別人分享都能夠一眼看出哪些變數,比起用數字來索引也不容易出錯;
- 另外一個是考慮到最後細篩變數是要看VIF和WOE結果的,需要將相關的結果輸出保存到磁碟中,以字元型的數組作為自定義函數的參數也更加的方便。
舉個例子,如果df
為保存自變數和因變數數據的數據框,featurecols
為保存自變數變數名的字元型數組,自定義函數代碼如下:
MyivPlot <- function(df,variableName){ ivmatrix <- as.data.frame(iv.mult(df,"default",vars = variableName)) ivmatrixname <- paste(variableName, "_woe.csv", sep = "") woeoutputpath <- str_c(projectPath, "output", "woe", ivmatrixname, sep = "/") print(woeoutputpath) #保存woe結果 write_csv(ivmatrix, woeoutputpath) IVplot <- iv.plot.woe(iv.mult(df,"default",vars = variableName, summary=FALSE)) plotname <- paste(variableName,".jpg",sep = "") IVplotoutputpath <- str_c(projectPath,"output","IVplot", plotname, sep="/") print(IVplotoutputpath) #保存woe圖 ggsave(filename = IVplotoutputpath, plot = IVplot) IVplot}
則遍歷整個數組,保存所有變數的WOE結果和圖的代碼如下:
for (i in 2:length(reducecols)) { variableName <- str_sub(reducecols[i], 1, -5) MyivPlot(as.data.frame(df), variableName)}
注意下,原來reducecols
數組當中的變數是編碼過後的帶_woe
後綴的,但是iv.mult()
函數本身的vars
參數要求的是原變數名,所以在這個過程當中需要藉助stringr包中的一些函數,比如str_sub()
以及str_c()
等函數對變數名進行處理。
評分卡計算
- 評分卡的分值刻度通過將分值表示為比率對數的線性表達式: ,其中, A與B是常數, 壞好比率 為一個客戶違約的估計概率與正常的估計概率的比率, 為邏輯回歸的因變數,即
- 常數A和B的值可以通過兩個假設代入上式計算得到:
基準壞好比率(odds0)
對應基準分值(points0)
- 壞好比率翻倍的分數
PDO(Points to Double the Odds)
- 解上述兩方程,可以得到:
分值分配。將邏輯回歸公式代入評分卡分值公式,可以得到 其中, 為最終進入模型的自變數且已經轉換為WOE值, 為邏輯回歸的變數係數, 為邏輯回歸的截距, 為上頁求得的刻度因子。 為變數 對應的評分, 為基礎分(也可將基礎分值平均分配給各個變數)。
- R中代碼實現:
#邏輯回歸建模fit <- glm(default~.,family=binomial(link=logit),data=train)#將變數參數賦給coecoe = fit$coefficients#A,B初始化及基礎分計算A = 500B = 30/log(2)base_score = A-B*coe[1]#特定變數分值計算,假定變數名為Zhima,且為模型當中的第一個變數,此時取的是coe數組當中的第二個數值Zhima_score <- (-1)*B*Zhima_woe*coe[2]...#總分計算,將所有變數的分值以及基礎分累加total_score <- base_score + Zhima_score + ...
用戶分層
最後一步,按照一定信用分的區間來統計樣本中的好壞用戶的分布,然後根據分布的情況可以看出模型對好壞用戶的區分度,以及根據業務情況設定理論要拒絕的壞用戶比例,以及相應要拒絕的總用戶數。
後記
回過頭來看,這篇文章寫了將近一個月,實在拖拉。
轉眼轉行已經三個多月,本人試用期也已經完成,順利轉正。
僅以這篇文章總結下這段時間的工作,後面的挑戰還有更多,不斷克服,且行且探索!
推薦閱讀:
※SAS市場研究應用介紹:離散選擇分析
※手把手教你使用ggplot2繪製折線圖
※《Python數據挖掘》筆記(七) 自動化文本摘要
※2017年歷史文章匯總|機器學習
※Kaggle Titanic Data Analysis(Top 1.6%)經驗分享