一瞧挤、信貸風控簡介
信貸風控是數(shù)據(jù)挖掘算法最成功的應用之一,這在于金融信貸行業(yè)的數(shù)據(jù)量很充足,需求場景清晰及豐富材部。
信貸風控簡單來說就是判斷一個人借了錢后面(如下個月的還款日)會不會按期還錢东亦。更專業(yè)來說杏节,信貸風控是還款能力及還款意愿的綜合考量,根據(jù)這預先的判斷為信任依據(jù)進行放貸典阵,以此大大提高了金融業(yè)務效率奋渔。
與其他機器學習的工業(yè)場景不同,金融是極其厭惡風險的領域壮啊,其特殊性在于非常側重模型的解釋性及穩(wěn)定性嫉鲸。業(yè)界通常的做法是基于挖掘多維度的特征建立一套可解釋及效果穩(wěn)定的規(guī)則及風控模型對每筆訂單/用戶/行為做出判斷決策。
其中歹啼,對于(貸前)申請前的風控模型玄渗,也稱為申請評分卡--A卡座菠。A卡是風控的關鍵模型,業(yè)界共識是申請評分卡可以覆蓋80%的信用風險藤树。此外還有貸中行為評分卡B卡浴滴、催收評分卡C卡,以及反欺詐模型等等也榄。
A卡(Application score card)巡莹。目的在于預測申請時(申請信用卡、申請貸款)對申請人進行量化評估甜紫。
B卡(Behavior score card)降宅。目的在于預測使用時點(獲得貸款、信用卡的使用期間)未來一定時間內(nèi)逾期的概率囚霸。
C卡(Collection score card)腰根。目的在于預測已經(jīng)逾期并進入催收階段后未來一定時間內(nèi)還款的概率。
一個好的特征拓型,對于模型和規(guī)則都是至關重要的额嘿。像申請評分卡--A卡,主要可以歸到以下3方面特征:
1劣挫、信貸歷史類: 信貸交易次數(shù)及額度册养、收入負債比、查詢征信次數(shù)压固、信貸歷史長度球拦、新開信貸賬戶數(shù)、額度使用率帐我、逾期次數(shù)及額度坎炼、信貸產(chǎn)品類型、被追償信息拦键。(信貸交易類的特征重要程度往往是最高的谣光,少了這部分歷史還款能力及意愿的信息,風控模型通常直接就廢了芬为。)
2萄金、基本資料及交易記錄類:年齡、婚姻狀況、學歷煤痕、工作類型及年薪、工資收入、存款AUM熬的、資產(chǎn)情況、公積金及繳稅晾咪、非信貸交易流水等記錄(這類主要是從還款能力上面綜合考量的。還可以結合多方核驗資料的真?zhèn)我约肮灿孟袷謾C號的圆、身份證號等團伙欺詐信息,用來鑒別欺詐風險半火。需要注意的越妈,像性別、膚色钮糖、地域梅掠、種族、宗教信仰等類型特征使用要謹慎店归,可能模型會有效果阎抒,但也會導致算法歧視問題。)
3消痛、公共負面記錄類: 如破產(chǎn)負債且叁、民事判決、行政處罰秩伞、法院強制執(zhí)行逞带、涉賭涉詐黑名單等(這類特征不一定能拿得到數(shù)據(jù),且通常缺失度比較高纱新,對模型貢獻一般展氓,更多的是從還款意愿/欺詐維度的考慮)
二、申請評分卡(A卡)全流程
實戰(zhàn)部分我們以經(jīng)典的申請評分卡為例脸爱,使用的中原銀行個人貸款違約預測比賽的數(shù)據(jù)集遇汞,使用信用評分python庫--toad、樹模型Lightgbm及邏輯回歸LR做申請評分模型阅羹。(注:文中所涉及的一些金融術語勺疼,由于篇幅就不展開解釋了,疑問之處 可以谷歌了解下哈捏鱼。)
2.1 模型定義
申請評分模型定義主要是通過一系列的數(shù)據(jù)分析確定建模的樣本及標簽执庐。
首先,補幾個金融風控的術語的說明导梆。概念模糊的話轨淌,可以回查再理解下:
逾期期數(shù)(M) :指實際還款日與應還款日之間的逾期天數(shù),并按區(qū)間劃分后的逾期狀態(tài)看尼。M取自Month on Book的第一個單詞递鹉。(注:不同機構所定義的區(qū)間劃分可能存在差異)
M0:當前未逾期(或用C表示,取自Current)
M1: 逾期1-30日
M2:逾期31-60日
M3:逾期61-90日
M4:逾期91-120日
M5:逾期121-150日
M6:逾期151-180日
M7+:逾期180日以上
觀察點:樣本層面的時間窗口藏斩。 用于構建樣本集的時間點(如2010年10月申請貸款的用戶)躏结,不同環(huán)節(jié)定義不同,比較抽象狰域,這里舉例說明:如果是申請模型媳拴,觀察點定義為用戶申貸時間黄橘,取19年1-12月所有的申貸訂單作為構建樣本集;如果是貸中行為模型屈溉,觀察點定義為某個具體日期塞关,如取19年6月15日在貸、沒有發(fā)生逾期的申貸訂單構建樣本集子巾。
觀察期:特征層面的時間窗口帆赢。構造特征的相對時間窗口,例如用戶申請貸款訂前12個月內(nèi)(2009年10月截至到2010年10月申請貸款前的數(shù)據(jù)都可以用线梗, 可以有用戶平均消費金額椰于、次數(shù)、貸款次數(shù)等數(shù)據(jù)特征)缠导。設定觀察期是為了每個樣本的特征對齊廉羔,長度一般根據(jù)數(shù)據(jù)決定。一個需要注意的點是僻造,只能用此次申請前的特征數(shù)據(jù)憋他,不然就會數(shù)據(jù)泄露(時間穿越,用未來預測過去的現(xiàn)象)髓削。
表現(xiàn)期:標簽層面的時間窗口竹挡。定義好壞標簽Y的時間窗口,信貸風險具有天然的滯后性立膛,因為用戶借款后一個月(第一期)才開始還錢揪罕,有得可能還了好幾期才發(fā)生逾期。
對于現(xiàn)成的比賽數(shù)據(jù)宝泵,數(shù)據(jù)特征的時間跨度(觀察期)好啰、數(shù)據(jù)樣本、標簽定義都是已經(jīng)提前分析確定下來的儿奶。但對于實際的業(yè)務來說框往,數(shù)據(jù)樣本及模型定義其實也是申請評分卡的關鍵之處。畢竟實際場景里面可能沒有人扔給你現(xiàn)成的數(shù)據(jù)及標簽(好壞定義闯捎,有些公司的業(yè)務會提前分析好給建模人員)椰弊,然后只是跑個分類模型那么簡單。
確定建模的樣本量及標簽瓤鼻,也就是模型從多少的數(shù)據(jù)樣本中學習如何分辨其中的好秉版、壞標簽樣本。如果樣本量稀少茬祷、標簽定義有問題清焕,那學習的結果可想而知也會是差的。(對于建模樣本量的確定,經(jīng)驗上肯定是滿足建模條件的樣本越多越好秸妥,一個類別最好有幾千以上的樣本數(shù)借卧。)
但對于標簽的定義,可能我們直觀感覺是比較簡單筛峭,比如“好用戶就是沒有逾期的用戶, 壞用戶就是在逾期的用戶”陪每,但具體做量化起來會發(fā)現(xiàn)并不簡單影晓,有兩個方面的主要因素需要考量:
- 【壞的定義】逾期多少天算是壞客戶。比如:只逾期2天算是建模的壞客戶檩禾?
根據(jù)巴塞爾協(xié)議的指導挂签,一般逾期超過90天(M4+)的客戶,即定義為壞客戶盼产。更為通用的饵婆,可以使用“滾動率”分析方法(Roll Rate Analysis)確定多少天算是“壞”,基本方法是統(tǒng)計分析出逾期M期的客戶多大概率會逾期M+1期(同樣的戏售,我們不太可能等著所有客戶都逾期一年才最終確定他就是壞客戶侨核。一來時間成本太高,二來這數(shù)據(jù)樣本會少的可憐)灌灾。如下示例搓译,我們通過滾動率分析各期逾期的變壞概率。當前未逾期(M0)下個月保持未逾期的概率99.71%锋喜; 當前逾期M1些己,下個月繼續(xù)逾期概率為54.34%;當前M2下個月繼續(xù)逾期概率就高達90.04%嘿般。我們可以看出M2是個比較明顯的變壞拐點段标,可以以M2+作為壞樣本的定義。
- 【表現(xiàn)期】借貸申請的時間點(即:觀察點)之后要在多久的時間暴露表現(xiàn)下炉奴,才能比較徹底的確定客戶是否逾期逼庞。比如:借貸后觀察了一個客戶借貸后60天的那幾個分期的表現(xiàn)都是按時還款,就可以判斷他是好/壞客戶盆佣?
這也就是確定表現(xiàn)期往堡,常用的分析方法是Vintage分析(Vintage在信貸領域不僅可以用它來評估客戶好壞充分暴露所需的時間,即成熟期共耍,還可以用它分析不同時期風控策略的差異等)虑灰,通過分析歷史累計壞用戶暴露增加的趨勢,來確定至少要多少期可以比較全面的暴露出大部分的壞客戶痹兜。如下示例的壞定義是M4+穆咐,我們可以看出各期的M4+壞客戶經(jīng)過9或者10個月左右的表現(xiàn),基本上可以都暴露出來,后面壞客戶的總量就比較平穩(wěn)了对湃。這里我們就可以將表現(xiàn)期定位9或者10個月~
確定了壞的定義以及需要的表現(xiàn)期崖叫,我們就可以確定樣本的標簽,最終劃定的建模樣本:
- 好用戶:表現(xiàn)期(如9個月)內(nèi)無逾期的用戶樣本拍柒。
- 壞用戶:表現(xiàn)期(如9個月)內(nèi)逾期(如M2+)的用戶樣本心傀。
- 灰用戶:表現(xiàn)期內(nèi)有過逾期行為,但不到壞定義(如M2+)的樣本拆讯。注:實踐中經(jīng)常會把只逾期3天內(nèi)的用戶也歸為好用戶脂男。
比如現(xiàn)在的時間是2022-10月底,表現(xiàn)期9個月的話种呐,就可以取2022-01月份及之前申請的樣本(這也稱為 觀察點)宰翅,打上好壞標簽,建模爽室。
通過上面信用評分的介紹汁讼,很明顯的好用戶通常遠大于壞用戶的,這是一個類別極不均衡的典型場景阔墩,不均衡處理方法下文會談到嘿架。
2.2 讀取數(shù)據(jù)及預處理
本數(shù)據(jù)集的數(shù)據(jù)字典文檔、比賽介紹及本文代碼戈擒,可以到https://github.com/aialgorithm/Blog項目相應的代碼目錄下載
該數(shù)據(jù)集為中原銀行的個人貸款違約預測數(shù)據(jù)集眶明,個別字段有做了脫敏(金融的數(shù)據(jù)大都涉及機密)。主要的特征字段有個人基本信息筐高、經(jīng)濟能力搜囱、貸款歷史信息等等
數(shù)據(jù)有10000條樣本,38維原始特征柑土,其中isDefault為標簽蜀肘,是否逾期違約。
import pandas as pd
pd.set_option("display.max_columns",50)
train_bank = pd.read_csv('./train_public.csv')
print(train_bank.shape)
train_bank.head()
數(shù)據(jù)預處理主要是對日期信息稽屏、噪音數(shù)據(jù)做下處理扮宠,并劃分下類別、數(shù)值類型的特征狐榔。
# 日期類型:issueDate 轉換為pandas中的日期類型坛增,加工出數(shù)值特征
train_bank['issue_date'] = pd.to_datetime(train_bank['issue_date'])
# 提取多尺度特征
train_bank['issue_date_y'] = train_bank['issue_date'].dt.year
train_bank['issue_date_m'] = train_bank['issue_date'].dt.month
# 提取時間diff # 轉換為天為單位
base_time = datetime.datetime.strptime('2000-01-01', '%Y-%m-%d') # 隨機設置初始的基準時間
train_bank['issue_date_diff'] = train_bank['issue_date'].apply(lambda x: x-base_time).dt.days
# 可以發(fā)現(xiàn)earlies_credit_mon應該是年份-月的格式,這里簡單提取年份
train_bank['earlies_credit_mon'] = train_bank['earlies_credit_mon'].map(lambda x:int(sorted(x.split('-'))[0]))
train_bank.head()
# 工作年限處理
train_bank['work_year'].fillna('10+ years', inplace=True)
work_year_map = {'10+ years': 10, '2 years': 2, '< 1 year': 0, '3 years': 3, '1 year': 1,
'5 years': 5, '4 years': 4, '6 years': 6, '8 years': 8, '7 years': 7, '9 years': 9}
train_bank['work_year'] = train_bank['work_year'].map(work_year_map)
train_bank['class'] = train_bank['class'].map({'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6})
# 缺失值處理
train_bank = train_bank.fillna('9999')
# 區(qū)分 數(shù)值 或類別特征
drop_list = ['isDefault','earlies_credit_mon','loan_id','user_id','issue_date']
num_feas = []
cate_feas = []
for col in train_bank.columns:
if col not in drop_list:
try:
train_bank[col] = pd.to_numeric(train_bank[col]) # 轉為數(shù)值
num_feas.append(col)
except:
train_bank[col] = train_bank[col].astype('category')
cate_feas.append(col)
print(cate_feas)
print(num_feas)
2.3 lightgbm評分卡建模
如果是用Lightgbm建模做違約預測薄腻,簡單的數(shù)據(jù)處理收捣,基本上代碼就結束了。lgb樹模型是集成學習的強模型庵楷,自帶缺失罢艾、類別變量的處理楣颠,特征上面不用做很多處理,建模非常方便咐蚯,模型效果通常不錯童漩,還可以輸出特征的重要性。
(By the way春锋,申請評分卡業(yè)界用邏輯回歸LR會比較多矫膨,因為模型簡單,解釋性也比較好)期奔。
def model_metrics(model, x, y):
""" 評估 """
yhat = model.predict(x)
yprob = model.predict_proba(x)[:,1]
fpr,tpr,_ = roc_curve(y, yprob,pos_label=1)
metrics = {'AUC':auc(fpr, tpr),'KS':max(tpr-fpr),
'f1':f1_score(y,yhat),'P':precision_score(y,yhat),'R':recall_score(y,yhat)}
roc_auc = auc(fpr, tpr)
plt.plot(fpr, tpr, 'k--', label='ROC (area = {0:.2f})'.format(roc_auc), lw=2)
plt.xlim([-0.05, 1.05]) # 設置x豆拨、y軸的上下限,以免和邊緣重合能庆,更好的觀察圖像的整體
plt.ylim([-0.05, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate') # 可以使用中文,但需要導入一些庫即字體
plt.title('ROC Curve')
plt.legend(loc="lower right")
return metrics
# 劃分數(shù)據(jù)集:訓練集和測試集
train_x, test_x, train_y, test_y = train_test_split(train_bank[num_feas + cate_feas], train_bank.isDefault,test_size=0.3, random_state=0)
# 訓練模型
lgb=lightgbm.LGBMClassifier(n_estimators=5,leaves=5, class_weight= 'balanced',metric = 'AUC')
lgb.fit(train_x, train_y)
print('train ',model_metrics(lgb,train_x, train_y))
print('test ',model_metrics(lgb,test_x,test_y))
from lightgbm import plot_importance
plot_importance(lgb)
2.4 LR評分卡建模
LR即邏輯回歸脚线,是一種廣義線性模型搁胆,因為其模型簡單、解釋性良好邮绿,在金融行業(yè)是最常用的渠旁。
也正因為LR過于簡單,沒有非線性能力船逮,所以我們往往需要通過比較復雜的特征工程顾腊,如分箱WOE編碼的方法,提高模型的非線性能力挖胃。
關于LR的原理及優(yōu)化方法杂靶,強烈推薦閱讀下:
下面我們通過toad實現(xiàn)特征分析、特征選擇酱鸭、特征分箱及WOE編碼
2.4.1 特征選擇
# 數(shù)據(jù)EDA分析
toad.detector.detect(train_bank)
# 特征選擇,根據(jù)相關性 缺失率吗垮、IV 等指標
train_selected, dropped = toad.selection.select(train_bank,target = 'isDefault', empty = 0.5, iv = 0.05, corr = 0.7, return_drop=True, exclude=['earlies_credit_mon','loan_id','user_id','issue_date'])
print(dropped)
print(train_selected.shape)
# 劃分訓練集 測試集
train_x, test_x, train_y, test_y = train_test_split(train_selected.drop(['loan_id','user_id','isDefault','issue_date','earlies_credit_mon'],axis=1), train_selected.isDefault,test_size=0.3, random_state=0)
2.4.2 卡方分箱
# 特征的卡方分箱
combiner = toad.transform.Combiner()
# 訓練數(shù)據(jù)并指定分箱方法
combiner.fit(pd.concat([train_x,train_y], axis=1), y='isDefault',method= 'chi',min_samples = 0.05,exclude=[])
# 以字典形式保存分箱結果
bins = combiner.export()
bins
通過特征分箱,每一個特征被離散化為各個分箱凹髓。
接下來就是LR特征工程的特色處理了--手動調(diào)整分箱的單調(diào)性烁登。
這一步的意義更多在于特征的業(yè)務解釋性的約束,對于模型的擬合效果影響不一定是正面的蔚舀。這里我們主觀認為大多數(shù)特征的不同分箱的壞賬率badrate應該是滿足某種單調(diào)關系的饵沧,而起起伏伏是不太好理解的。如征信查詢次數(shù)這個特征赌躺,應該是分箱數(shù)值越高狼牺,壞賬率越大。(注:如年齡特征可能就不滿足這種單調(diào)關系)
我們可以查看下ebt_loan_ratio這個變量的分箱情況寿谴,根據(jù)bad_rate趨勢圖锁右,并保證單個分箱的樣本占比不低于0.05,去調(diào)整分箱,達到單調(diào)性咏瑟。(其他的特征可以按照這個方法繼續(xù)調(diào)整拂到,單調(diào)性調(diào)整還是挺耗時的)
adj_var = 'scoring_low'
#調(diào)整前原來的分箱 [560.4545455, 621.8181818, 660.0, 690.9090909, 730.0, 775.0]
adj_bin = {adj_var: [ 660.0, 700.9090909, 730.0, 775.0]}
c2 = toad.transform.Combiner()
c2.set_rules(adj_bin)
data_ = pd.concat([train_x,train_y], axis=1)
data_['type'] = 'train'
temp_data = c2.transform(data_[[adj_var,'isDefault','type']], labels=True)
from toad.plot import badrate_plot, proportion_plot
# badrate_plot(temp_data, target = 'isDefault', x = 'type', by = adj_var)
# proportion_plot(temp_data[adj_var])
from toad.plot import bin_plot,badrate_plot
bin_plot(temp_data, target = 'isDefault',x=adj_var)
-
調(diào)整前
-
調(diào)整后
# 更新調(diào)整后的分箱
combiner.set_rules(adj_bin)
combiner.export()
2.4.3 WOE編碼
接下來就是對各個特征的分箱做WOE編碼,通過WOE編碼給各個分箱不同的權重码泞,提升LR模型的非線性兄旬。
#計算WOE,僅在訓練集計算WOE余寥,不然會標簽泄露
transer = toad.transform.WOETransformer()
binned_data = combiner.transform(pd.concat([train_x,train_y], axis=1))
#對WOE的值進行轉化领铐,映射到原數(shù)據(jù)集上。對訓練集用fit_transform,測試集用transform.
data_tr_woe = transer.fit_transform(binned_data, binned_data['isDefault'], exclude=['isDefault'])
data_tr_woe.head()
## test woe
# 先分箱
binned_data = combiner.transform(test_x)
#對WOE的值進行轉化宋舷,映射到原數(shù)據(jù)集上绪撵。測試集用transform.
data_test_woe = transer.transform(binned_data)
data_test_woe.head()
2.4.4 訓練LR
使用woe編碼后的train數(shù)據(jù)訓練模型。對于金融風控這種極不平衡的數(shù)據(jù)集祝蝠,比較常用的做法是做下極少類的正采樣或者使用代價敏感學習class_weight='balanced'音诈,以增加極少類的學習權重∫锵粒可見:《一文解決樣本不均衡(全)》
對于LR等弱模型细溅,通常會發(fā)現(xiàn)訓練集與測試集的指標差異(gap)是比較少的,即很少過擬合現(xiàn)象儡嘶。
# 訓練LR模型
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(class_weight='balanced')
lr.fit(data_tr_woe.drop(['isDefault'],axis=1), data_tr_woe['isDefault'])
print('train ',model_metrics(lr,data_tr_woe.drop(['isDefault'],axis=1), data_tr_woe['isDefault']))
print('test ',model_metrics(lr,data_test_woe,test_y))
2.4.5 評分卡應用
利用訓練好的LR模型喇聊,輸出(概率)分數(shù)分布表,結合誤殺率蹦狂、召回率以及業(yè)務需要可以確定一個合適分數(shù)閾值cutoff (注:在實際場景中誓篱,通常還會將概率非線性轉化為更為直觀的整數(shù)分score=A-B*ln(odds),方便評分卡更直觀凯楔、統(tǒng)一的應用燕鸽。)
train_prob = lr.predict_proba(data_tr_woe.drop(['isDefault'],axis=1))[:,1]
test_prob = lr.predict_proba(data_test_woe)[:,1]
# Group the predicted scores in bins with same number of samples in each (i.e. "quantile" binning)
toad.metrics.KS_bucket(train_prob, data_tr_woe['isDefault'], bucket=10, method = 'quantile')
當預測這用戶的概率大于設定閾值,意味這個用戶的違約概率很高啼辣,就可以拒絕他的貸款申請啊研。