您的位置:首页 > 其它

个人贷款违约预测模型

2018-10-08 15:10 1141 查看

1 项目介绍

本项目通利用Kaggle平台predict-loan-defaulters (网盘下载提取码: tkup)贷款数据,通过逻辑回归模型来对这些数据进行预测判断,构建贷款违约预测模型,建立预测模型,预测正处于贷款期间的人的违约的概率 。

业务理解

在贷款管理方面,如果可以通过构建量化模型对客户的信用等级进行一定的区分。得知了每个账户的违约概率后,可以预估一下未来的坏账比例,及时做好资金安排。也可以对违约概可能性较高的客户进行更加频繁的“关怀”,及时发现问题,以避免损失。
在这个量化模型中,被解释变量为二分类变量,因此需要构建一个排序类分类模型。而排序类分类模型中常使用的算法是逻辑回归。

1.2 数据介绍
实际业务中的一个人可以拥有多个账户号(account_id),一个账户号(account_id)可以对应有多个顾客(client_id),即多个顾客共享一个账户号(account_id),但是每个帐户号(account_id)的所有者(即最高权限者)只能是一人。
账户号(account_id)与客户号(client_id)的对应关系,在表“disposition”中进行列示;
表“Loan”为银行提供给账户号(account_id)的服务;
表“Credit card”为银行提供给的顾客(client_id)的服务,每个客户可以申请一张信用卡;
贷款为基于账户的服务,一个账户(account_id)在一个时点最多只能有一笔贷款。
本次数据建模分析共用了八个数据表:

2 数据处理

2.1 导入数据

import pandas as pd
import os
os.chdir("data")    # 数据文件存放在"data"文件夹里
loanfile = os.listdir()
createVar = locals()
for i in loanfile:
if i.endswith("txt"):
createVar[i.split('.')[0]] = pd.read_csv(i, encoding = 'gbk',sep=';')
print(i.split('.')[0])
accounts
card
clients
disp
district
loans
order
trans
  • 预览数据
loans.head()

loans.info()

2.2 生成被解释变量bad_good

贷款表(loans)中的还款的状态可分为 A:代表合同终止,没问题B:代表合同终止,贷款没支付C:代表合同处于执行期,至今正常;D:代表合同处于执行期,欠债状态。对数据进行转换,使A=0,B、D=1,C=2

bad_good = {'B':1, 'D':1, 'A':0, 'C': 2}
loans['bad_good'] = loans.status.map(bad_good)
loans.head()

2.3 数据整理

  • 借款人的年龄、性别
data2 = pd.merge(loans, disp, on = 'account_id', how = 'left')
data2 = pd.merge(data2, clients, on = 'client_id', how = 'left')
data2=data2[data2.type=='所有者']
data2.head()

  • 借款人居住地的经济状况
data3 = pd.merge(data2, district, left_on = 'district_id', right_on = 'A1', how = 'left')
data3.head()

  • 变异系数的计算:先计算每个账户余额的平均值和标准差,然后用标准差/均值。
data_4temp1 = pd.merge(loans[['account_id', 'date']],
trans[['account_id','type','amount','balance','date']],
on = 'account_id')
data_4temp1.columns = ['account_id', 'date', 'type', 'amount', 'balance', 't_date']
data_4temp1 = data_4temp1.sort_values(by = ['account_id','t_date'])

# 日期格式转换:将data_4temp1的date和t_date列数据类型转换为时间类型
data_4temp1['date']=pd.to_datetime(data_4temp1['date'])
data_4temp1['t_date']=pd.to_datetime(data_4temp1['t_date'])
data_4temp1.tail()

  • 账户余额进行清洗
# 将data4_t1的amount和balance列数据类型转换为数值类型
data_4temp1['balance2'] = data_4temp1['balance'].map(
lambda x: int(''.join(x[1:].split(','))))
data_4temp1['amount2'] = data_4temp1['amount'].map(
lambda x: int(''.join(x[1:].split(','))))
data_4temp1.head()

  • 根据取数窗口(设置为1年)提取交易数据
import datetime
data_4temp2 = data_4temp1[data_4temp1.date>data_4temp1.t_date][
data_4temp1.date<data_4temp1.t_date+datetime.timedelta(days=365)]
data_4temp2.tail()

  • 得到变异系数
data_4temp3 = data_4temp2.groupby('account_id')['balance2'].agg({'avg_balance':'mean', 'stdev_balance':'std'})
data_4temp3['cv_balance'] = data_4temp3[['avg_balance','stdev_balance']].apply(lambda x: x[1]/x[0],axis = 1)
data_4temp3.head()

  • 平均支出和平均收入的比例
type_dict = {'借':'out','贷':'income'}
data_4temp2['type1'] = data_4temp2.type.map(type_dict)
data_4temp4 = data_4temp2.groupby(['account_id','type1'])[['amount2']].sum()

data_4temp5 = pd.pivot_table(
data_4temp4, values = 'amount2',
index = 'account_id', columns = 'type1')
data_4temp5.fillna(0, inplace = True)
data_4temp5['r_out_in'] = data_4temp5[
['out','income']].apply(lambda x: x[0]/x[1], axis = 1)
data4 = pd.merge(data3, data_4temp3, left_on='account_id', right_index= True, how = 'left')
data4 = pd.merge(data4, data_4temp5, left_on='account_id', right_index= True, how = 'left')
data4.head()

  • 计算贷存比,贷收比
data4['r_lb'] = data4[['amount','avg_balance']].apply(lambda x: x[0]/x[1],axis = 1)
data4['r_lincome'] = data4[['amount','income']].apply(lambda x: x[0]/x[1],axis = 1)
data4.head()

3 构建Logistic模型

数据挖掘方法分为分类和描述两大类,其中预测账户的违约情况属于分类模型。使用逻辑回归对刚才创建的数据建立模型,建模语句如下。

  • 提取状态为C的用于预测。其它样本随机抽样,建立训练集与测试集
data_model=data4[data4.status!='C']
for_predict=data4[data4.status=='C']

train = data_model.sample(frac=0.7, random_state=1235).copy()
test = data_model[~ data_model.index.isin(train.index)].copy()
print(' 训练集样本量: %i \n 测试集样本量: %i' %(len(train), len(test))
训练集样本量: 195
测试集样本量: 84
  • 向前法 筛选有用的字段名
def forward_select(data, response):
import statsmodels.api as sm
import statsmodels.formula.api as smf
remaining = set(data.columns)
remaining.remove(response)
selected = []
current_score, best_new_score = float('inf'), float('inf')
while remaining:
aic_with_candidates=[]
for candidate in remaining:
formula = "{} ~ {}".format(
response,' + '.join(selected + [candidate]))
aic = smf.glm(
formula=formula, data=data,
family=sm.families.Binomial(sm.families.links.logit)
).fit().aic
aic_with_candidates.append((aic, candidate))
aic_with_candidates.sort(reverse=True)
best_new_score, best_candidate=aic_with_candidates.pop()
if current_score > best_new_score:
remaining.remove(best_candidate)
selected.append(best_candidate)
current_score = best_new_score
print ('aic is {},continuing!'.format(current_score))
else:
print ('forward selection over!')
break

formula = "{} ~ {} ".format(response,' + '.join(selected))
print('final formula is {}'.format(formula))
model = smf.glm(
formula=formula, data=data,
family=sm.families.Binomial(sm.families.links.logit)
).fit()
return(model)
candidates = ['bad_good', 'A1', 'GDP', 'A4', 'A10', 'A11', 'A12','amount', 'duration',
'A13', 'A14', 'A15', 'a16', 'avg_balance', 'stdev_balance',
'cv_balance', 'income', 'out', 'r_out_in', 'r_lb', 'r_lincome']
data_for_select = train[candidates]
lg_m1 = forward_select(data=data_for_select, response='bad_good')
lg_m1.summary().tables[1]

  • 可见,预测效果最佳的两个因素是:
    贷存比 (r_lb ) ,可反映客户用钱的需求度
    存款变异系数(cv_balance),可反映客户经济状况是否稳定
  • 假设显著性水平设定为0.01,由上图可知,逻辑回归各变量都已通过显著性检验,满足要求

4 模型验证

要验证模型的预测能力,通过ROC曲线和AUC来评估模型的拟合能力。

from sklearn.metrics import roc_curve,auc
import matplotlib.pyplot as plt
fpr,tpr,threshold=roc_curve(test.bad_good, lg_m1.predict(test))
rocauc=auc(fpr,tpr)
plt.plot(fpr,tpr,'b',label='AUC=%0.2f'% rocauc)
plt.legend(loc='lower right')
plt.plot([0,1],[0,1],'r--')
plt.title('ROC curve')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.show()


从上图可知,AUC值为0.88,说明模型的预测能力较好。

5 测试模型

  • 在这个案例中,贷款状态为”C”的帐户是尚没有出现违约的合同未到期客户。这些贷款客户中有些人的违约可能性较高,需要业务人员重点关注。一旦发现问题时,可以及时处理,挽回损失。可以通过以下语句得到每笔贷款的违约”概率”。
for_predict['prob']=lg_m1.predict(for_predict)
for_predict[['account_id','prob']].head()


结论:由测试模型得出账户号为1071,5313的客户违约的概率比较高,需要注意

6 参考文献

  1. 宽胖子. 数据科学实战:Python篇(案例:个人贷款违约预测模型)
  2. bombTree. 基于逻辑回归模型 下的简单用户违约预测分析 .csdn
  3. qq_39963880.全栈技术详解1-个人贷款违约预测模型 .csdn

附:百度网盘 predict-loan-defaulters .zip 提取码: tkup

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: