催收评分卡实战
? 催收評分卡分為滾動率模型、還款率模型和失聯模型,市面上介紹C卡的模型較少,本人將收集到的貸后催收評分卡的視頻教程整理列舉如下:
https://www.bilibili.com/video/BV1pJ411y7yA?p=7
https://www.bilibili.com/video/BV1ZE411V7Mk/
觀察期和表現期
? 本次催收評分卡是M1滾動率模型,即預測當前處于M1狀態的用戶在本周期內回收(出催)的概率。
? 貸后催收評分卡需要不斷積累建模樣本,所以前期通常會制定一些貸后緩催策略,后期積累了一定樣本之后再用評分卡來實現更精細化的切分。關于催收評分卡的觀察期和表現期,大致有以下3種做法(假定觀察期為6個月,表現期為2個月):
第一種:鎖定觀察期
? 觀察期為放款之后的前6個月,表現期為第7、8個月,也就是將mob賬齡鎖定。這種方法的觀察點為第六期期末的時間,會因為放款月的不同在不斷移動,但是觀察期+觀察點為賬齡的前6期。
一般C卡要包含完整的年度數據,即觀察點至少需要包含3月、6月、9月、12月四個時間節點,因此這種情況下至少要有18個月的樣本數據。
第二種:鎖定表現期
? 表現期鎖定為某兩個月,比如2020年3月和4月。建模樣本則為截止2020年3月賬齡大于6期的所有樣本。放款月越早,觀察點所處的mob就越大。觀察期可以取最近6期,也可以取2020年3月之前的所有賬期。
第三種:觀察期和表現期都在移動
? 這種方法就是將每一個訂單6期之后的數據按賬單日拆分成多條,比如一個用戶的還款表現為"FFFFFF1212",那么入模的樣本就會有"FFFFFF12"和"FFFFFF1212"兩條。前面一條的觀察期為前6期,表現期為第7、8期;后一條觀察期為前8期,表現期為第9、10期,以此類推。這種方法可以擴充建模樣本數量,但是X變量的衍生會比較復雜。
本文將采用第三種方法進行評分卡制作,第三種方法的難點在于X變量的衍生。
數據集劃分
? 數據集劃分為訓練集、測試集、跨時間驗證集(5:3:2)。訓練集進行模型訓練,如果需要進行調參的話還需要對訓練集進行切分,劃分成訓練集和驗證集。測試集用于查看模型的泛化能力。跨時間驗證集則是監控隨著時間變化對模型的預測效果產生的影響。
這里注意一點,分箱的過程應該是基于訓練集進行,然后將跨時間驗證集的數據根據分箱結果進行映射。之前為了省事直接在數據集上進行分箱,然后再根據放款月份取訓練集和跨時間驗證集,這樣會造成模型過擬合。
變量選取
? 貸后催收評分卡常用到的變量有催收行為數據、逾期行為數據、歷史還款數據、客戶檔案數據以及第三方數據。
催收行為數據:
歷史還款數據:
客戶檔案數據:
第三方數據:
? 以上是番茄風控老騎士的催收評分卡課程中用到的變量,僅供參考。
? 以下是結合公司實際數據情況,用到的評分卡變量,主要用到mob表和還款計劃表,基于這兩張表進行變量的衍生。
? 特征衍生是催收評分卡制作過程中的重中之重了,一般會衍生很多時間切片變量,反映借款人最近一段時間內的還款能力和意愿。相對于前兩種觀察期和表現期的取法,一種是固定賬齡mob,一種是固定表現月,這兩種方法取時間切片變量的時候都相對比較容易。如果是觀察期和表現期都不固定的這種,特征衍生的過程會復雜一點。
時間切片變量衍生
? 首先,會計算出截止每一期的賬單日的還款歷史狀態。大概情況如下:
? 對每一行的repayment_history取長度等于mob的位數就可以得到當期的還款歷史字段,然后就可以繼續衍生當期而言的近3期、近6期的逾期行為變量。這里只能衍生逾期狀態的行為變量,如果需要衍生逾期天數的行為變量,需要根據還款計劃表進行計算。
? 首先,根據還款計劃表計算每一期的逾期天數,如果至今未還的話就用當前時間代替。然后衍生一個類似于還款歷史的字段,只不過是逾期天數組合成的字段。后面的操作就和逾期狀態的處理一樣了。
? 同理,還款金額的時間切片變量也可以這樣衍生。
# 生成逾期天數的List overdue_dict=(df_all.groupby('app_id')['overdue_days'].apply(lambda x:list(x))).to_dict() df_all['overdue_days_list']=df_all['app_id'].map(overdue_dict) # 生成實際還款金額的List pay_amt_dict=df_all.groupby('app_id')['all_pay_amt'].apply(lambda x:list(x)).to_dict() df_all['pay_amt_list']=df_all['app_id'].map(pay_amt_dict)變量穿越
? 變量穿越是指X變量的表現時間超過了Y變量,即出現用Y去預測Y的情況,這在貸后評分卡中是很容易犯的。這種變量一旦入模的后果就是變量的IV值極高(一般大于0.5就會有這種情況),而且模型的KS較高。
? 思考兩個變量,首次逾期天數、首逾3天發生期數這兩個變量是否可以入模?
首次逾期天數:用戶發生首次逾期的天數。
? 比如一條樣本的還款歷史為FFFFFF12,Y變量為M1-M2,此時用戶的首逾天數一定會大于30天,就會出現用Y去預測Y的情況。因為首逾天數大于30天,就意味著一定從M1遷徙到M2。
? 但是如果將這個首次逾期天數調整一下,如果該條記錄為用戶首次逾期,則這個變量為0。這樣就會避免變量穿越的問題了。
首逾3天發生期數:首次逾期3天以上發生的期數。
? 比如樣本的還款歷史為FFFFFF1112,首次逾期3天以上發生在第9期,即第三個1的地方。這條樣本會被拆成FFFFFF11和FFFFFF111和FFFFFF1112三條樣本。而對于FFFFFF11這個樣本,首逾3天以上發生在第9期,這個字段一共才取到第8期,所以會出現變量穿越。
變量分箱
變量有類別型變量和數值型變量。
類別型變量:
降基處理:將類別占比小于某個閾值的類別劃為一箱。
bad_rate編碼:將每一箱按照壞樣本比例映射成數值變量。但是變量會失去原有的解釋性。
數值型變量:
將數值型變量和bad_rate編碼轉換過來的變量進行卡方分箱。
? 分箱之后需要看每個變量的單調性,一般要求每一箱之間的bad_rate單調。但是如果是年齡這種變量,可能無法保證完全單調,只要業務上能解釋得通就可以。
? 左圖是近3期逾期次數的壞樣本率情況,可以發現近3期逾期次數越高,變壞的可能性越低。說明這部分用戶是習慣性逾期,每次都會逾期但是經過催收都會回正。
? 右圖是近6期M1-M0的次數,99是將2、3降基處理之后的值,可以發現M1-M0回正次數越多,變壞的概率就會越低。
? 個人覺得評分卡的精髓在于如何分箱,因為分箱方法的不同會導致WOE、IV值的不同,進而影響后續建模的一系列動作。如何選擇合適的分箱方法和調整分箱,本人還需要更加深入地學習。
變量篩選
主要就是進行IV值(>0.02)、相關性(<0.7)、回歸系數(為正)。代碼如下:
# 相關性剔除 def forward_delete_corr(df,col_list,threshold=None):"""df:數據集col_list:變量list集合threshold: 相關性設定的閾值return:相關性剔除后的變量"""list_corr = col_list[:]for col in list_corr:corr = df.loc[:,list_corr].corr()[col]corr_index= [x for x in corr.index if x!=col]# corr_values = [x for x in corr.values if x!=1]corr_values = list(corr[corr.index.isin(corr_index)])for i,j in zip(corr_index,corr_values):if abs(j)>=threshold:list_corr.remove(i)return list_corr? 注意,相關性剔除時col_list的變量要按照IV值從大到小的順序,這樣才能保證剔除的是IV值較小的那個變量。
# 邏輯回歸系數符號篩選,在篩選前需要做woe轉換 def forward_delete_coef(x_train,y_train):"""x_train -- x訓練集y_train -- y訓練集return :coef_col回歸系數符號篩選后的變量lr_coe:每個變量的系數值"""col_list = list(x_train.columns)coef_col = []for col in col_list:coef_col.append(col)x_train2 = x_train.loc[:,coef_col]sk_lr = LogisticRegression(C=0.1,class_weight='balanced').fit(x_train2,y_train)coef_df = pd.DataFrame({'col':coef_col,'coef':sk_lr.coef_[0]})if coef_df[coef_df.coef<0].shape[0]>0:coef_col.remove(col)# print(coef_col)x_new_train = x_train.loc[:,coef_col]lr = LogisticRegression(C=0.1,class_weight='balanced').fit(x_new_train,y_train)lr_coe = pd.DataFrame({'col':coef_col,'coef':lr.coef_[0]})return coef_col,lr_coe? 這個函數中邏輯回歸的系數需要和建模時候的系數一致,不然就會出現剔除完之后的變量建模之后,又出現系數為負的情況。系數為負,說明變量之間仍然存在多重共線性,而且會給單變量得分的解釋性造成困擾。關于多重共線性的影響列舉如下:
建模
? 說一下邏輯回歸調參,一般評分卡建模中不調參也是可以的。
調參主要用到網格搜索算法,主要調整C和penalty兩個參數。
網格調參的代碼如下:
def pm_search(model,pm,scale,X,y):#調參函數param_test = {pm:scale}gsearch = GridSearchCV(LogisticRegression(class_weight='balanced',penalty='l1'), param_grid = param_test, scoring='roc_auc', cv=5 )gsearch.fit(X,y)score_gs=gsearch.grid_scores_#各項參數的aucscore_pm=[[pm,scale[loc],score_gs[loc][1]] for loc in range(len(score_gs))]print(score_pm)parameter=[str(value[1]) for value in score_pm]scores=[value[2] for value in score_pm]#AUC分數繪圖sns.set(rc={"figure.figsize":(10,6)})sns.set(style='darkgrid',palette='muted',color_codes=True)plt.plot(parameter,scores,scaley =False)#最優參數合并listbest_para=parameter[scores.index(max(scores))]return [pm,best_para]? 模型的KS曲線、ROC曲線等評估情況這里就不再詳述,有興趣的可以參看之前評分卡的系列文章。催收評分卡只是提升催收效率的第一步,對催收效果影響最大的因素還是催收人員本身。后續基于模型的分析和策略的制定才是更重要的。這里列出一些催收評分卡課程中提及到的策略:
【作者】:Labryant
【原創公眾號】:風控獵人
【簡介】:某創業公司策略分析師,積極上進,努力提升。乾坤未定,你我都是黑馬。
【轉載說明】:轉載請說明出處,謝謝合作!~
總結
- 上一篇: 常用机器学习算法原理及推导
- 下一篇: 迁移学习和冷启动