利用LendingClub數據建模

本文算是《數據分析工具之Python大法》系列的大結局。本來只是想展示下Python在信用風險數據分析領域的基本使用,誰知道絮絮叨叨寫了這麼多篇,說精簡不精簡,說詳細不詳細,非常令人抓狂。最近由於所有精力花在一個1000多個變數的數據的特徵工程上,也沒來得及更新知乎文章,要不是@Luo Patrick昨天提醒,真是不知道拖延症到什麼時候。另外由於Python只是一個通用編程語言,實際上在風險建模方面很多工具都是自己寫的或者借鑒網路上的開源腳本,這個工具集大概有近千行代碼,顯然不適合在本文直接展示出來,所以本文很多地方都只會有結果,不會有代碼。

言歸正傳,所謂信用風險模型,簡單的理解就是將歷史發生的借貸行為抽象出來,我們相信有共同行為特徵的一群人一定時間內在違約這件事情上具有相似的行為模式,因為我們從歷史數據中提取各個維度的特徵對應這些特徵的履約表現,從而預測將來有這些特徵的人的違約概率。這個裡面就有幾個關鍵的問題:

  • 在預測違約之前首先要定義違約,

  • 提取出對預測違約能起到作用特徵變數,

  • 提取特徵的對象以及時間範圍,

  • 將特徵與違約之間的關係進行擬合,

  • 檢驗預測的效果。

回到LC這個案例:

  • 我這裡定義的違約是逾期15天以上,

  • 特徵變數的提取和處理,有時候又叫特徵工程,實際上在傳統的評分卡模型里這部分工作是最耗時間的,它需要業務經驗和數據表現進行結合分析,不過現在越來越多的特徵提取是通過機器學習的方法進行自動提取,本文實際上為了省時間也簡單地利用了GBDT這個演算法去評判特徵變數的重要性,以及結合自己的業務判斷進行特徵變數的提取,此外因為偏展示所以本文也沒有對特徵變數進行組合和衍生,

  • 本來分析是基於2016年一季度的放款數據,但是根據業務的常識,除了像欺詐類型的客戶,通常情況下在放款一段時間後違約表現才可能充分和平穩。根據經驗法則,小微貸款需要6個月左右的時間。所以我特意使用了LC去年6月到12月的數據,

  • 本文主要採用傳統的logistic regression進行線性擬合,
  • 至於驗證,分成兩塊,一塊是樣本內的驗證,一塊是樣本外的驗證,本文不對樣本外的驗證進行操作,實際上模型還沒有出來就可以預知在樣本外的驗證效果會非常差,原因是本模型的取樣並不是針對所有人群的隨機抽樣,而是將LC篩選通過後的客戶作為樣本,這裡其實可以引出很重要的一個話題就是拒絕推論,不做展開了,後續再抽時間專門講。

一、清洗模型數據,LC2015年下半年的數據總共有269000條,數據欄位有117個,具體數據下載地址我在第一篇文章有提供鏈接。如何在這117個欄位中提取出模型要使用的特徵變數實際上可能是這篇文章里最耗時間的地方,數據預處理的部分前面幾篇文章都有穿插著講,本文不細講,主要預處理是:1、貸後的相關變數除了target變數,其餘直接剔除,因為貸後表現在客戶申請時是沒有的,如果進入模型實際上就成了未來變數;2、缺失率太高的變數直接剔除,本文是按65%的閾值來剔除的;3、數值變數中所有值方差太小接近常量的變數剔除,因為不能提供更多信息;4、按業務邏輯完全不可解釋的變數直接剔除,5、分類變數中unique值大於20的直接剔除;6、將object類型數據轉換成數值類型;7、缺失值單獨當作一類,填充-999。

二、因為英文水平有限,對這些變數的邏輯並不能做到百分比理解,所以在進行WOE編碼前,利用GBDT演算法跑一下變數的重要性進行概覽

"""n這個xgb_select是我利用xgboost寫的腳本,以後完善了再做分享n"""nxgb_feature_score = xgb_select(model_data,target,cols)n

三、對特徵的重要性有個初步了解後,分析每一個特徵變數,並將變數根據業務邏輯進行分類,因為很多時候有些變數都有不錯的表現,但其實他們背後的信息量其實是一樣的,比如說dti和annual_inc,一個是收入負債比一個是收入絕對值,實際兩者是存在很多的相關性的,而我們下面要使用的邏輯回歸對於共線性問題是很敏感的,所以通過特徵變數的分類來手工剔除一些變數。實際上在工作中大家還會利用VIF(方差膨脹因子)來檢測共線性的變數。

方差膨脹因子一般取小於5的變數,不過有時候根據業務邏輯判斷,也會選擇大於5的變數

在上一篇文章中有提到LC的風險分組,實際上那就是LC風險模型的輸出結果,我們可以通過下面一些圖可以直觀的看到上面那些特徵變數和最後風險分組直接是存在一定線性關係的,我們進行特徵工程的目的就是找出所有對後續風險表現可能有線性關係或這說區分能力的變數,比如:

1、FICO分

sns.pointplot(x="grade", y="fico_range_low", data=analysis_data,n color="c",order=list(ABCDEFG),estimator=np.median,ci=95,capsize=.2)n

2、住房性質

analysis_data_home = analysis_data.groupby([grade,home_ownership])[[issue_d]].count().apply(lambda x : x/x.sum(level=0)).unstack(level=1)n .reset_index().set_index(grade)n stack(level=0).reset_index(level=1, drop=True)nanalysis_data_home.plot.barh(stacked=True,figsize=(15,8)).legend(loc=center left, bbox_to_anchor=(1, 0.5))n

3、貸款用途

analysis_data_purpose = analysis_data.groupby([grade,purpose]) [[issue_d]].count().apply(lambda x : x/x.sum(level=0)).unstack(level=1)n .reset_index().set_index(grade)n .stack(level=0).reset_index(level=1, drop=True)nanalysis_data_purpose.plot.barh(stacked=True,figsize=(45,30),xlim=(0,1),fontsize=40).legend(loc=center left, fontsize=40,bbox_to_anchor=(1, 0.5))n

4、收入水平

analysis_data_inc_v = analysis_data.groupby([grade,verification_status,inc_bin])[[issue_d]].count().apply(lambda x : x/x.sum(level=0)).unstack(level=1)n .stack(level=0).reset_index(level=2, drop=True)n nsns.factorplot(x="grade", y="annual_inc", hue="verification_status", data=analysis_data,order=list(ABCDEFG),size=15,palette="Paired")n

以上些例子中的這些變數實際上是我根據我的業務判斷直接挑選的,可以看出或多或是和後面的風險分組存在一定的線性關係,也就是可以推斷LC的模型中可能用到了這些變數。

四、WOE編碼,在傳統的評分卡製作中,都喜歡把連續變數離散化也就是將有相類似表現段的特徵劃為一類,我通常的做法是用qcut先將變數劃分為30個箱,然後根據woe和badrate對相鄰箱進行合併,同時考慮業務邏輯進行邊界點的選擇。(至於WOE,IV包括後面要講的GINI,KS,AUC,PSI等等建模常用的統計指標計算邏輯、指標意義非常重要,後續專門做一篇講吧,)

以FICO分為例:

在我寫的腳本里通常會輸出上圖所示的統計指標:min,max,total,bin_pct,bad,good,badrate,samplebadrate,woe,iv,gini,bad_cum,good_cum,ks

我們根據相鄰的woe值相近就合併的原則,合併後效果如下:

在這一步可以看到最終這個變數的IV值,在經驗法則里IV小於0.05的變數預測能力都是非常差的,在業務邏輯允許的情況下,可以直接剔除該變數。最後將剩下的變數用WOE值替換在分箱區間的原始值,完成WOE編碼,結果類似下圖:

五、通過逐步回歸(StepWise Logistic Regression)來確定最終變數,逐步回歸在Python上是沒有現成的包的,用SAS的同學可以直接跑。(我是根據網上某大牛公開的代碼進行修改的,以後完善了再公開吧,目前腳本存在運行效率的問題,而且樣本量大還容易造成MemoryError,以至於此次最後跑模型的時候,我對好客戶進行了欠抽樣,只選擇剩下2萬條好客戶數據才勉強跑完逐步回歸,這用於算是Python目前使用於風控建模領域的重大缺點吧)

六、將最後選定的數據按訓練集和測試集進行7:3切分,利用Python里Statsmodels包跑邏輯回歸(為了直接出圖和統計數據,也是在Statsmodels和scikit-learn的基礎上自己寫的腳本,來實現自動畫圖的功能,所以要用Python的同學就要做好很多東西都要自己造輪子的準備),下面就是我花了一下午時間倒騰出來的結果:

下面是測試數據集的驗證結果:

再來看邏輯回歸數據概率對應的BadRate:

上面兩張圖有沒有讓你想起我在上一篇文章最後的那張LC自己的風險分組,對的,理論上我也可以根據我上面兩張圖裡不同預測概率對於badrate也分出ABCDEFG7組,當然很多公司是把概率轉成SCORE,其實效果是一樣的。

結論:從中午忙活到現在,20萬數據到最後的模型,應該說實際工作中沒人會只花半天來建一張評分卡,提取特徵進行特徵工程有時間都需要花半個月時間。所以從文中樣本內的驗證結果看,我倒是感到欣慰,AUC和KS低了點,但是輸出的風險分組實際上比我想像中要單調,說明區分能力還是可以的。

最後,給各位觀眾真誠地說聲對不起,我可能是知乎專欄里寫文章最不用心的人了,包括一堆的錯別字,包括倉促的準備,真心抱歉,在後續很長一段時間,比如半年可能都會這樣,因為敝司的事情真心多,多,多

晚安


推薦閱讀:

基於TCP的python聊天程序
100行深度學習文本分類
Python進階課程筆記(五)

TAG:Python | 信用风险 | 数据建模 |