当前位置:   article > 正文

基于Python的银行信贷风险可视化与预警建模_风险预算模型 python

风险预算模型 python

银行信贷风险评估模型代码分析

一、背景概要

信贷业务又称为信贷资产或贷款业务,是商业银行最重要的资产业务,通过放款收回本金和利息,扣除成本后获得利润,所以信贷是商业银行的主要赢利手段。

二、代码解析

1 相关技术背景

XGBoost是一套提升树可扩展的机器学习系统。目标是设计和构建高度可扩展的端到端提升树系统。提出了一个理论上合理的加权分位数略图来计算候选集。引入了一种新颖的稀疏感知算法用于并行树学习。提出了一个有效的用于核外树形学习的缓存感知块结构。用缓存加速寻找排序后被打乱的索引的列数据的过程。XGBoost是一个树集成模型,他将K(树的个数)个树的结果进行求和,作为最终的预测值。

2 算法解析

使用机器学习建模的一般流程。分为两大部分:数据处理和模型学习。第一部分需要大量的知识对原始数据进行清理及特征提取;第二部分模型学习,涉及长时间的模型参数调整,调整方向和策略需要根据经验来灵活调整。当模型效果不理想时,考虑的调整策略:

  1. 调节正负样本的权重参数。
  2. 更换模型算法。
  3. 同时几个使用模型进行预测,然后取去测的最终结果。
  4. 使用原数据,生成新特征。

1. Logistic函数

Logistic回归模型中的因变量只有1和0(发生于不发生)两种。假设在p个独立自变量x1,x2…xp作用下,y取1的概率是p = P(y = 1|X)取0的概率是1-p,取1和取0的概率之比为:P/(1-P);称为事件的优势比(odds),对odds取自然对数得Logistic变换。

2.Logistic回归建模步骤

(a)根据分析目的设置指标变量(因变量和自变量),然后收集数据,根据收集到的数据,对特征再次进行筛选;

#特征重要程度情况

ax = xgb.plot_importance(model)

fig = ax.figure

fig.set_size_inches(15,10)

(b)y取1的概率是p= P(y= 1|X), 取0概率是1-p。用

ln(p/(1−p))和自变量列出线性回归方程,估计出模型中的回归系数;

(c)进行模型检验。模型有效性的检验指标有很多,最基本的有正确率,其次有混淆矩阵、ROC曲线、KS值等。

(d)模型应用:输入自变量的取值,就可以得到预测变量的值,或者根据预测变量的值去控制自变量的取值。

实例:

gender

age

dist

edu

job

lmt

basicLevel

x_0

x_1

2

27

640500

0

8

5.963

3

0

0

2

25

640600

0

3

6.467

3

0

0

2

37

641200

70

5

0.596

1

0

0

2

29

340821

0

4

6.3

3

0

0

2

22

732628

0

2

6.7

2

0

0

利用Scikit-Learn对这个数据进行逻辑回归分析。首先进行特征筛选,特征筛选的方法有很多,主要包含在Scikit_Learn 的feature_ selection 库中,比较简单的有通过F检验(f_ regression)来给出各个特征的F值和p值,从而可以筛选变量(选择F值大的或者p值小的特征)。其次有递归特征消除( Recursive Feature Elimination, RFE)和稳定性选择(StabilitySelection)等比较新的方法。这里使用了稳定性选择方法中的随机逻辑回归进行特征筛选,然后利用筛选后的特征建立逻辑回归模型,输出平均正确率。

3.数据源内容解读

数据集,可以看到数据样本中有很多列属性。

train_df = pd.read_csv("D:/files/train.csv")

test_df = pd.read_csv("D:/files/test.csv")

4.Python主要数据预处理函数

在数据挖掘中,海量的原始数据中存在着大量不完整(有缺失值)、不一致、有异常的数据,严重影响到数据挖掘建模的执行效率,甚至可能导致挖掘结果的偏差,所以进行数据清洗就显得尤为重要,数据清洗完成后接着进行或者同时进行数据集成、转换、规约等一系列的处理,该过程就是数据预处理。数据预处理一方面是要提高数据的质量,另一方面是要让数据更好地适应特定的挖掘技术或工具。

5.二分类

对于二分类模型,其实既可以构建分类器,也可以构建回归。

# predict train

predict_train = model.predict(dtrain)

train_auc = evaluate_score(predict_train, y_train)

# predict validate

predict_valid = model.predict(dvalid)

valid_auc = evaluate_score(predict_valid, y_valid)

print('train auc = {:.7f} , valid auc = {:.7f}\n'.format(train_auc, valid_auc))

三、模型训练

数据处理需要花费大量的精力,说明在机器学习中数据准备的工作很重要,有了好的数据才能预测出好的分类结果,对于二分类问题,一般情况下,首选逻辑回归。

#模型训练

model = xgb.train(dict(xgb_params),

                      dtrain,

                      evals=watchlist,

                      verbose_eval=50,

                      early_stopping_rounds=100,

                      num_boost_round=4000)

#利用最佳迭代次数,再次利用全量数据训练模型

print('---> training on total dataset to predict test and submit')

model = xgb.train(dict(xgb_params),

                  dtrain_all,

                  num_boost_round=best_num_boost_rounds)

# predict validate

predict_valid = model.predict(dvalid)

valid_auc = evaluate_score(predict_valid, y_valid)

print('预测的验证集 AUC 指标:', valid_auc)

===> feature count: 103

scale_pos_weight =  1

train: 91826, valid: 10203, test: 30000

[0] train-auc:0.50000 valid-auc:0.50000

Multiple eval metrics have been passed: 'valid-auc' will be used for early stopping.

Will train until valid-auc hasn't improved in 100 rounds.

[50] train-auc:0.64097 valid-auc:0.65167

[100] train-auc:0.65153 valid-auc:0.67749

[150] train-auc:0.67276 valid-auc:0.72217

[200] train-auc:0.68959 valid-auc:0.73652

[250] train-auc:0.71319 valid-auc:0.73802

[300] train-auc:0.74216 valid-auc:0.73880

Stopping. Best iteration:

[241] train-auc:0.70966 valid-auc:0.73982

train auc = 0.7646057 , valid auc = 0.7385212

---> cv train to choose best_num_boost_round

[0] train-auc:0.50000 test-auc:0.50000

[100] train-auc:0.65790 test-auc:0.64860

[200] train-auc:0.69347 test-auc:0.66955

[300] train-auc:0.74312 test-auc:0.68096

[400] train-auc:0.79174 test-auc:0.69092

[500] train-auc:0.81697 test-auc:0.69518

[600] train-auc:0.83385 test-auc:0.69656

查看预测结果

"""

定义方法:评价得分模型

"""

def evaluate_score(predict, y_true):

    #通过sklearn的roc_curve函数计算false positive rate和true positive rate以及对应的thresholds

    #理论上thresholds应该取遍所有的predict(即模型预测值)

    #thresholds就是predict(即模型预测值)逆序排列后的结果

    false_positive_rate, true_positive_rate, thresholds = roc_curve(y_true, predict, pos_label=1)

    auc_score = auc(false_positive_rate, true_positive_rate)#计算ROC曲线下的面积

    return auc_score

train_df.head()#返回数据

y_train_all = train_df['target']

del train_df['id']

del train_df['target']

train_df.head()

#ROC 曲线

fpr, tpr, _ = roc_curve(y_valid, predict_valid)

roc_auc = auc(fpr, tpr)

plt.figure(figsize=(10,10))

plt.plot(fpr, tpr, color='darkorange',

         lw=2, label='ROC curve (area = %0.2f)' % roc_auc)

plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')

plt.xlim([-0.02, 1.0])

plt.ylim([0.0, 1.05])

plt.xlabel('False Positive Rate')

plt.ylabel('True Positive Rate')

plt.title('ROC curve')

plt.legend(loc="lower right")

plt.show()

四、数据探索分析

1 加载数据(训练集和测试集样本)

train_df = pd.read_csv("D:/files/train.csv")#将csv文件读入并转化为数据框形式

test_df = pd.read_csv("D:/files/test.csv")#将csv文件读入并转化为数据框形式

"""

训练集样本数: (102029, 105)

测试集样本数: (30000, 105)

"""

print("训练集样本数:", train_df.shape)#读取矩阵长度,如shape[0]是读取矩阵第一维的长度

print("测试集样本数:", test_df.shape)#读取矩阵长度,如shape[0]是读取矩阵第一维的长度

2 违约用户数量分布

#违约用户数量分布

plt.figure(figsize=(10,6))#表示figure 的大小为宽、长(单位为inch)

#使用normalize=True参数进行计数排序得出占比,赋值给train_df的target

tmp = train_df["target"].value_counts(normalize=True)#train.csv的DA列

_, ax = plt.subplots()#返回一个包含figure和axes对象的元组

sns.barplot(x=tmp.index.tolist(), y=tmp.values, ci=None, ax=ax)#按坐标绘制条形图

#将一个可遍历的数据对象组合为一个索引序列,同时列出数据和数据下标

for i, j in enumerate(tmp.sort_index()):#根据列数据/行数据排序

    #可视化text()函数

    ax.text(i, j, round(j, 5), ha="center", fontsize=12)

del tmp

gc.collect()#清理内存

plt.show()#按坐标绘制条形图,显示该条形图

3 违约用户性别分布

#违约用户性别分布

plt.figure(figsize=(10,6))#表示figure 的大小为宽、长(单位为inch)

#使用normalize=True参数进行计数排序得出占比,赋值给train_df的gender

tmp = train_df["gender"].value_counts(normalize=True)

#返回一个包含figure和axes对象的元组

_, ax = plt.subplots()

sns.barplot(x=tmp.index.tolist(), y=tmp.values, ci=None, ax=ax)#按坐标绘制条形图

for i, j in enumerate(tmp.sort_index()):#根据列数据/行数据排序

  ax.text(i, j, round(j, 5), ha="center", fontsize=12) #可视化text()函数

del tmp

gc.collect()#清理内存

plt.show()

4 违约用户年龄分布

#违约用户年龄分布

plt.figure(figsize=(20,6))

# 对 年龄 age 维度进行统计不同值出现的个数,数值进行归一化处理

tmp = train_df["age"].value_counts(normalize=True)

ax = plt.subplot(111)#单个整数编码的子绘图网格参数,“111”表示“1×1网格,第一子图

sns.barplot(x=tmp.index.tolist(), y=tmp.values, ci=None, ax=ax)#按坐标绘制条形图

for i, j in enumerate(tmp.sort_index()):#根据列数据/行数据排序

    ax.text(i, j, round(j, 5), ha="center", fontsize=12)#可视化text()函数

del tmp

gc.collect()#清理内存

plt.show()#

5 违约用户工作单位类型分布

#违约用户工作单位类型分布

plt.figure(figsize=(20,6))

# 对 用户工作单位类型 job 维度进行统计不同值出现的个数,数值进行归一化处理

tmp = train_df["job"].value_counts(normalize=True)

ax = plt.subplot(111)#单个整数编码的子绘图网格参数,“111”表示“1×1网格,第一子图

sns.barplot(x=tmp.index.tolist(), y=tmp.values, ci=None, ax=ax)#按坐标绘制条形图

for i, j in enumerate(tmp.sort_index()):#根据列数据/行数据排序

    ax.text(i, j, round(j, 5), ha="center", fontsize=12)#可视化text()函数

del tmp

gc.collect()#清理内存

plt.show()

6 不同借贷产品类型的违约比例分布

# 不同借贷产品类型的违约比例分布 将数据集按照借贷产品类型进行分组统计,分别计算不同组违约的比例

plt.figure(figsize=(20,6))

tmp = train_df.groupby("loanProduct")["target"].mean().to_frame("ratio").reset_index()

#返回一个包含figure和axes对象的元组

_, ax = plt.subplots()

sns.barplot(x="loanProduct", y="ratio", ci=None, data=tmp, ax=ax)  # DataFrame,数组或数组列表,可选

for i, j in enumerate(tmp["ratio"]):#根据列数据/行数据排序

    ax.text(i, j, round(j, 5), ha="center", fontsize=12)

del tmp

gc.collect()#清理内存

plt.show()

7 不同借贷产品类型的违约随时间变化趋势

#不同借贷产品类型的违约随时间变化趋势

tmp_1 = train_df.loc[train_df["loanProduct"] == 1, "target"].rolling(500).mean().dropna().reset_index(drop=True)

tmp_2 = train_df.loc[train_df["loanProduct"] == 2, "target"].rolling(500).mean().dropna().reset_index(drop=True)

tmp_3 = train_df.loc[train_df["loanProduct"] == 3, "target"].rolling(500).mean().dropna().reset_index(drop=True)

plt.figure(figsize=(20,6))#违约用户工作单位类型分布

ax = plt.subplot(131)#建立子图

tmp_1.plot(ax=ax)

ax = plt.subplot(132)

tmp_2.plot(ax=ax)

ax = plt.subplot(133)

tmp_3.plot(ax=ax)

plt.show()

8 预授信金额分布

#预授信金额分布

plt.figure(figsize=(15, 5))

ax = plt.subplot(121)

sns.kdeplot(train_df[train_df['target'] == 1]['lmt'])

ax.set_title('Normal User')

ax = plt.subplot(122)

sns.kdeplot(train_df[train_df['target'] == 0]['lmt'])

ax.set_title('Risk User')

plt.show()

9 基础评级分布

#基础评级分布

plt.figure(figsize=(15, 5))

ax = plt.subplot(121)

sns.countplot(train_df[train_df['target'] == 1]['basicLevel'])

ax.set_title('Normal User')

ax = plt.subplot(122)

sns.countplot(train_df[train_df['target'] == 0]['basicLevel'])

ax.set_title('Risk User')

plt.show()

10 用户的民族分布情况

#用户的民族分布情况

plt.figure(figsize=(20, 5))

ax = plt.subplot(121)

sns.countplot(train_df[train_df['target'] == 1]['ethnic'])

ax.set_title('Normal User')

ax = plt.subplot(122)

sns.countplot(train_df[train_df['target'] == 0]['ethnic'])

ax.set_title('Risk User')

plt.show()

11 用户最高学历分布情况

#用户最高学历分布情况

plt.figure(figsize=(20, 5))

ax = plt.subplot(121)

sns.countplot(train_df[train_df['target'] == 1]['highestEdu'])

ax.set_title('Normal User')

ax = plt.subplot(122)

sns.countplot(train_df[train_df['target'] == 0]['highestEdu'])

ax.set_title('Risk User')

plt.show()

12 用户的联系人关系分布

#用户的联系人关系分布

plt.figure(figsize=(20, 5))

ax = plt.subplot(121)

sns.countplot(train_df[train_df['target'] == 1]['linkRela'])

ax.set_title('Normal User')

ax = plt.subplot(122)

sns.countplot(train_df[train_df['target'] == 0]['linkRela'])

ax.set_title('Risk User')

plt.show()

13 用户申请信用卡时段分布

#用户申请信用卡时段分布

plt.figure(figsize=(20, 5))

ax = plt.subplot(121)

sns.countplot(train_df[train_df['target'] == 1]['setupHour'])

ax.set_title('Normal User')

ax = plt.subplot(122)

sns.countplot(train_df[train_df['target'] == 0]['setupHour'])

ax.set_title('Risk User')

plt.show()

14 用户申请信用卡时段分布

#用户申请信用卡时段分布

plt.figure(figsize=(20, 5))

ax = plt.subplot(121)

sns.countplot(train_df[train_df['target'] == 1]['weekday'])

ax.set_title('Normal User')

ax = plt.subplot(122)

sns.countplot(train_df[train_df['target'] == 0]['weekday'])

ax.set_title('Risk User')

plt.show()

15 用户失效信用卡数分布

#用户失效信用卡数分布

plt.figure(figsize=(20, 5))

ax = plt.subplot(121)

sns.countplot(train_df[train_df['target'] == 1]['ncloseCreditCard'])

ax.set_title('Normal User')

ax = plt.subplot(122)

sns.countplot(train_df[train_df['target'] == 0]['ncloseCreditCard'])

ax.set_title('Risk User')

plt.show()

16 用户未支付个人贷款金额分布

#用户未支付个人贷款金额分布

plt.figure(figsize=(20, 5))

ax = plt.subplot(121)

sns.kdeplot(train_df[train_df['target'] == 1]['unpayIndvLoan'])

ax.set_title('Normal User')

ax = plt.subplot(122)

sns.kdeplot(train_df[train_df['target'] == 0]['unpayIndvLoan'])

ax.set_title('Risk User')

plt.show()

17 用户未支付其他贷款金额分布

#用户未支付其他贷款金额分布

plt.figure(figsize=(20, 5))

ax = plt.subplot(121)

sns.kdeplot(train_df[train_df['target'] == 1]['unpayNormalLoan'])

ax.set_title('Normal User')

ax = plt.subplot(122)

sns.kdeplot(train_df[train_df['target'] == 0]['unpayNormalLoan'])

ax.set_title('Risk User')

plt.show()

18 用户五年内未支付贷款金额

#用户五年内未支付贷款金额

plt.figure(figsize=(20, 5))

ax = plt.subplot(121)

sns.kdeplot(train_df[train_df['target'] == 1]['5yearBadloan'])

ax.set_title('Normal User')

ax = plt.subplot(122)

sns.kdeplot(train_df[train_df['target'] == 0]['5yearBadloan'])

ax.set_title('Risk User')

plt.show()

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/939891
推荐阅读
相关标签
  

闽ICP备14008679号