個(gè)人貸款違約預(yù)測(cè)模型

案例背景

案例來源《python數(shù)據(jù)科學(xué):技術(shù)詳解與商業(yè)實(shí)踐》數(shù)據(jù)下載地址
該案例使用一套來自某銀行真實(shí)數(shù)據(jù)集構(gòu)建貸款違約預(yù)測(cè)模型

本案例遵循數(shù)據(jù)挖掘項(xiàng)目通用流程CRISP-DM進(jìn)行建模,流程如下:

  1. 項(xiàng)目理解
  2. 數(shù)據(jù)理解
  3. 數(shù)據(jù)準(zhǔn)備
  4. 模型構(gòu)建與評(píng)價(jià)
  5. 模型監(jiān)控
CRISP-DM

1.項(xiàng)目理解

原始數(shù)據(jù)中Loans.status表示貸款客戶的還款狀態(tài),其中A代表合同終止,沒問題;B代表合同終止,貸款沒有支付;C代表合同處于執(zhí)行期,至今 正常;D代表合同處于執(zhí)行期,欠債狀態(tài)。A類客戶表示客戶正常履行完合同無違約行為,BD類客戶表示有違約行為,通過ABD類客戶的個(gè)人信息,狀態(tài)信息以及行為信息,預(yù)測(cè)C類客戶在還款期內(nèi)是否會(huì)發(fā)生違約行為
項(xiàng)目預(yù)測(cè)變量為客戶是否違約,(違約為1,不違約為0)為二分類變量,因此需要構(gòu)建一個(gè)排序類分類模型,在排序類分類模型中,由于邏輯回歸容易實(shí)現(xiàn),可解釋性強(qiáng),為最常用排序類分類模型

2.數(shù)據(jù)理解

數(shù)據(jù)提供9張表,涉及客戶主記錄、帳號(hào)、交易、業(yè)務(wù)和信 用卡數(shù)據(jù);

  • 賬戶表(Accounts)
    每條記錄描述一個(gè)賬戶的靜態(tài)信息,共4500條


  • 客戶信息表(Clients)
    每條記錄描述了一個(gè)客戶的特征信息,共 5369 條


  • 權(quán)限分配表(Disp)
    每條記錄描述了客戶和賬戶之間的關(guān)系,以及客戶操作賬戶的權(quán)限 ,共5369條


  • 支付訂單表 (Orders)
    每條記錄代表描述了一個(gè)支付命令,共6471條


  • 交易表 (Trans)
    每條記錄代表每個(gè)賬戶上的一條交易,共1056320條


  • 貸款表(Loans)
    每條記錄代表某個(gè)賬戶的上的一條貸款信息,共682條


  • 信用卡(Cards)
    每條記錄描述了一個(gè)賬戶上的信用卡信息 ,共 892 條


  • 人口地區(qū)統(tǒng)計(jì)表 (District)
    每條記錄描述了一個(gè)地區(qū)的人口統(tǒng)計(jì)學(xué)信息,共77條



    數(shù)據(jù)實(shí)體ER圖

3.數(shù)據(jù)準(zhǔn)備

在篩選前我們要考慮一個(gè)時(shí)間窗口的問題,簡(jiǎn)單講就是銀行給用戶放款后,在下一個(gè)還款期銀行再記錄用戶是否發(fā)生逾期,由于客戶一年前的狀態(tài)信息比較有參考價(jià)值,這里根據(jù)放款時(shí)間來劃分時(shí)間窗口,選取的記錄為放款時(shí)間之前一年,構(gòu)建每個(gè)表的放款前特征。

基于業(yè)務(wù)理解及數(shù)據(jù)可靠度,可信度提取出如下解釋變量

os.chdir(r'C:\Users\Administrator\Desktop\Python_book\19Case\19_1Bankcredit')
createVar = locals()
for i in os.listdir():
    if i.split('.')[1] == 'csv':
        createVar[i.split('.')[0]] = pd.read_csv(i,encoding='gbk')
        print(i.split('.')[0])
loans['bad_good'] = loans.status.map({'B':1,'A':0,'D':1,'C':2})#定義因變量
loans.head()
disp = disp[disp['type']=='所有者']
data1 = pd.merge(loans,disp,how ='left',on='account_id')#將客戶貸款表作為主表,鏈接權(quán)限分配表
data2 = pd.merge(data1,clients,how='left',on='client_id')#通過權(quán)限表上面的client_id鏈接客戶信息表
data3 = pd.merge(data2,card,how='left',on='disp_id')#鏈接信用卡信息
data3.head()
data4 = pd.merge(data3,district,how='left',left_on='district_id',right_on='A1')#鏈接地區(qū)狀態(tài)信息
data4['date'] = pd.to_datetime(data4['date'])
data4['birth_date'] = pd.to_datetime(data4['birth_date'])#將字符串轉(zhuǎn)換為datatime時(shí)間序列
data4['age'] = round((data4['date']-data4['birth_date'])/np.timedelta64(365,'D'),0)#篩選出年齡
data4.head()
#篩選出所需的個(gè)人信息和狀態(tài)信息
data4.columns
data4 = data4[['account_id','amount', 'duration','payments','bad_good','sex','type_y', 'GDP',
       'A4', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'a16', 'age']]
data4.head()
#篩選出貸款前1年的交易數(shù)據(jù)
df = pd.merge(trans,loans,on='account_id')
df['date_x']= pd.to_datetime(df['date_x'])
df['date_y']= pd.to_datetime(df['date_y'])
#amount_x和balance為字符串類型,將其轉(zhuǎn)化為數(shù)值類型
df['amount_x'] = df['amount_x'].map(lambda x:''.join(x[1:].split(','))).astype(int)
df['balance'] = df['balance'].map(lambda x:''.join(x[1:].split(','))).astype(int)
#篩選出放款日前1年內(nèi)的至前一天的交易記錄
df = df[(df['date_x']<df['date_y'])&((df['date_x']+np.timedelta64(365,'D'))>df['date_y'])]
#篩選用戶一年內(nèi)結(jié)息總額
df1 = df[df['k_symbol']=='利息所得']
df1 = pd.DataFrame(df1.groupby('account_id')['amount_x'].sum())
df1.columns =['interest']
#賽選在本行是否有養(yǎng)老金和房屋貸款
df2 = df[(df['k_symbol']=='養(yǎng)老金')| (df['k_symbol']=='房屋貸款')]
#標(biāo)記是否在本行有房屋貸款
df2 = pd.DataFrame(df2.groupby('account_id')['k_symbol'].count())
df2['house_loan'] = '1'
del df2['k_symbol']
#篩選客戶一年內(nèi)收入和支出(總和)
df3 = pd.DataFrame(df.pivot_table(values='amount_x',index='account_id',columns='type',aggfunc=np.sum))
df3.columns = ['out','income']
#篩選客戶一年內(nèi)余額的均值和標(biāo)準(zhǔn)差
df4 = pd.DataFrame(df.groupby('account_id')['balance'].agg(['mean','std']))
df4.columns = ['balance_mean','balance_std']
#合并數(shù)據(jù)
data = pd.merge(df1,df2,how='left',left_index=True,right_index=True)
data = pd.merge(data,df3,left_index=True,right_index=True)
data = pd.merge(data,df4,left_index=True,right_index=True)
len(data)#查看數(shù)據(jù)條數(shù)是否與貸款表?xiàng)l數(shù)一致
data_modle = pd.merge(data4,data,left_on='account_id',right_index=True)

4.模型構(gòu)建與評(píng)價(jià)

該步驟按照SEMMA標(biāo)準(zhǔn)算法,分為數(shù)據(jù)采樣,變量分析探索,修改變量,構(gòu)建邏輯回歸,評(píng)價(jià)模型的優(yōu)劣,由于原始數(shù)據(jù)已經(jīng)準(zhǔn)備好,直接跳過第一步。

4.1變量分析探索

查看數(shù)據(jù)缺失情況

data_modle.isnull().sum()/len(data_modle)

其中type_y信用卡類型缺失率75%,該變量沒有可解釋性,故刪除
A12 1995年失業(yè)率 和 A15 1995犯罪率(千人) 有極小部分?jǐn)?shù)據(jù)缺失,填充中位數(shù)
house_loan 是否有房屋貸款,缺失值為沒有房屋貸款,填充字符’0‘

data_modle['A12'].fillna(data_modle['A12'].median(),inplace=True)
data_modle['A15'].fillna(data_modle['A12'].median(),inplace=True)
data_modle['house_loan'].fillna('0',inplace=True)
del data_modle['type_y']

將變量按照變量類型進(jìn)行分類

#因變量
y= 'bad_good'
#連續(xù)變量
var_c = ['amount', 'duration', 'payments', 'GDP',
       'A4', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'a16', 'age',
       'interest', 'out', 'income', 'balance_mean',
       'balance_std']
#分類變量
var_d = ['sex','house_loan']

兩個(gè)分類變量sex和house_loan 屬于二分類變量,將其二值化

data_modle['sex'] = data_modle['sex'].map({'男':1,'女':0})
data_modle['house_loan'] = data_modle['house_loan'].map({'1':1,'0':0})

查看各變量間的相關(guān)性

corr = data_modle[var_c+var_d].corr()
plt.figure(figsize=(12,9))
sns.heatmap(corr,vmax=1,annot=True)
4.2修改變量

從熱力圖中可以看出貸款信息,居住地信息,經(jīng)濟(jì)狀況信息內(nèi)各變量具有高相關(guān)性,需要通過選擇其中一個(gè)變量或者變量轉(zhuǎn)換篩選變量進(jìn)入模型
貸款信息中,保留amount貸款金額變量(應(yīng)該通過變量轉(zhuǎn)換 (月供*貸款期數(shù)-貸款金額)/貸款金額 計(jì)算出貸款利率,但是本案例通過計(jì)算利率為0,所以只保留貸款金額)
居住地信息,同過轉(zhuǎn)換保留兩個(gè)變量人均GDP(反應(yīng)當(dāng)?shù)亟?jīng)濟(jì)狀況),失業(yè)增長(zhǎng)率(一定程度上反應(yīng)當(dāng)?shù)谿DP增長(zhǎng)水平)
經(jīng)濟(jì)狀況信息,通過變量轉(zhuǎn)換保留三個(gè)變量,客戶放款前近一年總結(jié)息(一定程度上反應(yīng)客戶實(shí)際存款數(shù)額大?。?,收支比(消費(fèi)占收入比重,一定程度反應(yīng)客戶消費(fèi)水平),可用余額變異系數(shù)(客戶結(jié)余的波動(dòng),一定程度上反應(yīng)客戶生活狀態(tài)穩(wěn)定系數(shù))

data_modle['GDP_per'] = data_modle['GDP']/data_modle['A4']#人均GDP人民生活水平的一個(gè)標(biāo)準(zhǔn)
data_modle['unemployment'] = data_modle['A13']/data_modle['A12']#失業(yè)增長(zhǎng)率一定程度上反應(yīng)經(jīng)濟(jì)增長(zhǎng)率
data_modle['out/in'] =  data_modle['out']/data_modle['income']#消費(fèi)占收入比重,一定程度反應(yīng)客戶消費(fèi)水平
data_modle['balance_a']  =  data_modle['balance_std']/data_modle['balance_mean']#可用余額變異系數(shù)
var = ['sex','age','amount','GDP_per','unemployment','out/in','balance_a']
4.3構(gòu)建邏輯回歸
  1. 提取狀態(tài)為2(合同為履行完正常還款客戶)的樣本用于預(yù)測(cè),其他樣本隨機(jī)采樣,建立訓(xùn)練集和測(cè)試集,比例4:1
data_model = data_modle[var+[y]]
for_predict = data_model[data_model[y]==2]
data_model = data_model[data_model[y]!=2]
#定義自變量和因變量
X= np.array(data_model[var])
Y = np.array(data_model[y])
#將樣本數(shù)據(jù)建立訓(xùn)練集和測(cè)試集
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size = 0.2, random_state = 1234)
  1. 使用邏輯回歸L1正則化參數(shù),建模

L1正則化可以是一些不重要的變量回歸系數(shù)變零,達(dá)到篩選變量的目的
參考:https://zhuanlan.zhihu.com/p/25707761

from sklearn.linear_model import LogisticRegression
LR = LogisticRegression(penalty='l1')
clf = LR.fit(x_train,y_train)
y_pred = clf.predict(x_test)#預(yù)測(cè)測(cè)試集數(shù)據(jù)
clf.coef_#查看各變量的回歸系數(shù)

通過查看各變量的回歸系數(shù)可以看到'sex'和'GDP_per'字段被刪除

  1. 模型結(jié)果評(píng)價(jià)
from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))

模型的精確率0.87,召回率0.84,f1_score為0.82
繪制ROC曲線

from sklearn.metrics import roc_curve, auc
fpr, tpr, threshold = roc_curve(y_test, y_pred)
roc_auc = auc(fpr, tpr)
plt.plot(fpr, tpr, color='darkorange',label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy',  linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC_curve')
plt.legend(loc="lower right")
plt.show()

ROC曲線

AUC面積76%模型的解釋力度,一般要求在75%以上

總結(jié)

  1. 本項(xiàng)目按照CRISP-DM進(jìn)行建模,建模過程遵循SEMMA標(biāo)準(zhǔn)算法
  2. 本項(xiàng)目重點(diǎn)在寬表展開,數(shù)據(jù)提取以及衍生變量的選擇.進(jìn)一步提升模型解釋度,變量的選擇很重要,選取的幾個(gè)衍生變量也是根據(jù)自己的理解選擇的.實(shí)際中還是要對(duì)業(yè)務(wù)有深刻理解.
  3. 特征變量的篩選還可以選擇filter法和Wrapper法,參考https://blog.csdn.net/cymy001/article/details/79425960
  4. 提高模型精度可選用組合算法或者強(qiáng)模型,但可解釋度低
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容