数据集地址:
链接:https://pan.baidu.com/s/1vQgkQs1aTC-zm6zcDH4kKQ
提取码:6ois

1 数据说明与导入


导入必需的库和数据。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings("ignore")
%matplotlib inlineimport sklearn
from sklearn.model_selection import train_test_split # 分离数据集和测试集
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics # 一些评价指标
from sklearn.metrics import precision_recall_curve # 召回率
from sklearn.metrics import confusion_matrix # 混淆矩阵
from sklearn import preprocessing
df = pd.read_csv('./UCI_Credit_Card.csv') # 导入数据

2 数据初步探索

2.1 数据信息检查

df.head()

df.shape
df.info()
df.describe()

一共有30000名信用卡持卡人的信息,这些持卡人信用卡平均额度LIMIT_BAL为167484,但是标准差达到了129747,信用卡最大额度达到100万新台币,额度最小的仅有10000新台币,跨度非常大;我们已知2代表女性,1代表男性,性别SEX的平均值在1.6以上,说明女性在该样本中的占比明显高于男性。同时我们也发现与描述不符的异常数据,教育程度EDUCATION的最大值和最小值均在给定的字段描述之外,婚姻状况MARRIAGE有标记为3的点,PAY_1PAY_6的还款记录中出现了描述之外的-2,我们应逐一进行理解与清洗。

2.2 数据清洗

首先,查看教育程度。

df['EDUCATION'].value_counts()

2 14030
1 10585
3 4917
5 280
4 123
6 51
0 14
Name: EDUCATION, dtype: int64

教育程度标记为4,5,6的值都可以理解为“其他”,代表低于高中的学历。为了将学历按低到高进行排序,交换了标签1和标签3。

df['EDUCATION'].replace([1,3,4,5,6],[3,1,0,0,0],inplace=True)
df['EDUCATION'].value_counts()

2 14030
3 10585
1 4917
0 468
Name: EDUCATION, dtype: int64

将性别SEX数据中男性和女性标记为0和1,符合编程习惯。

df['SEX'].replace([1,2],[0,1],inplace=True)
df['SEX'].value_counts()

1 18112
0 11888
Name: SEX, dtype: int64

df['MARRIAGE'].value_counts()

2 15964
1 13659
3 323
0 54
Name: MARRIAGE, dtype: int64

df['MARRIAGE'].replace(3,0,inplace=True)
df['MARRIAGE'].value_counts()

2 15964
1 13659
0 377
Name: MARRIAGE, dtype: int64

最后,我们对标记还款状况的列 PAY_1 到PAY_6 也同样进行查看。首先取 PAY_1 一列为例子。

df['PAY_1'].value_counts()

0 14737
-1 5686
1 3688
-2 2759
2 2667
3 322
4 76
5 26
8 19
6 11
7 9
Name: PAY_1, dtype: int64

还款为-2,-1,0均应视为还清债务,我们将其统一标记为0。经过验证PAY_1PAY_6的数据具有同样特征,我们用iloc定位我们要替换的列,进行替换操作。

df.iloc[:,[6,7,8,9,10,11]] = df.iloc[:,[6,7,8,9,10,11]].replace([-1,-2],[0,0])
df.iloc[:,[6,7,8,9,10,11]].describe()
df['default.payment.next.month'].value_counts()[0]/df['default.payment.next.month'].value_counts()[1]

正负样本的比例大概是3.5:1,数据存在不平衡问题。

2.3 数据可视化与分析

2.3.1 数据分布情况

plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
sns.set(rc={'figure.figsize':(10,5),"font.size":15,'font.sans-serif':['SimHei'],"axes.titlesize":15,"axes.labelsize":15})
plt.title('信用额度分布图')
# 改变 matplotlib 颜色缩写词的解释方式
sns.set_color_codes("pastel")
# kde:是否绘制高斯核密度估计图 bins:直方图bins(柱)的数目
sns.distplot(df['LIMIT_BAL'],kde=True,bins=200, color="blue")
plt.xlabel("信用额度")plt.rcParams['figure.dpi'] = 1200 #为了使图片更加清晰
plt.show()


可以看到信用额度的分布很不均匀,少数人群的信用额度非常高,大部分人的信用额度集中在较低的值。

sns.set(rc={'figure.figsize':(10,5),"font.size":15,'font.sans-serif':['SimHei'],"axes.titlesize":15,"axes.labelsize":15})
#
sns.set_color_codes("pastel")
sns.displot(df['AGE'],kde=True,bins=59, color="green")
plt.xlabel("年龄")
plt.title('客户年龄分布图')
plt.show()

从图中能够发现,客户的年龄主要集中在20-40岁之间。

对于离散型变量SEX、EDUCATION,MARRIAGE,使用饼图查看数据的占比情况。

# 绘制多个子图,1行3列
fig = plt.subplots(3,figsize=(16,12))
sns.set(rc={'figure.figsize':(10,5),"font.size":15,'font.sans-serif':['SimHei'],"axes.titlesize":15,"axes.labelsize":15})# 绘制第一个子图
plt.subplot(1,3,1)
sex_count = df['SEX'].value_counts()
# 画饼图,设置扇形标签,设置百分比显示格式,一位小数百分比
sex_count.plot(kind='pie', labels=['女性','男性'], autopct='%1.1f%%')
plt.ylabel("")
plt.title('性别分布图')plt.subplot(1,3,2)
edu_count = df['EDUCATION'].value_counts()
edu_count.plot(kind='pie', labels=['本科', '研究生或以上','高中','其他'], autopct='%1.1f%%')
plt.title('教育情况分布图')
plt.ylabel("")plt.subplot(1,3,3)
mar_count = df['MARRIAGE'].value_counts()
mar_count.plot(kind='pie', labels=['未婚', '已婚','其他'], autopct='%1.1f%%')
plt.title('婚姻状况分布图')
plt.ylabel("")plt.show()


从本图中可以看出性别的分布不均匀,女性占比显著高于男性。教育情况上,72%的客户教育程度都在本科或以上。婚姻状况则显示已婚和未婚客户的数目差距不多。

2.3.2 结合违约情况查看数据分布

考察对于不同的性别,年龄和教育情况,客户的违约情况是否有着比较显著的区别。

sns.set(rc={'figure.figsize':(13,5),"font.size":15,'font.sans-serif':['SimHei'],"axes.titlesize":15,"axes.labelsize":15})
plt.figure()
# fig代表绘图窗口(Figure);ax代表这个绘图窗口上的坐标系(axis)
fig, ax = plt.subplots(1,3,figsize=(12,5))plt.subplot(1,3,1)
# 条形图,以x轴标签划分统计个数,再以hue标签统计违约与未违约的个数
ax=sns.countplot(x='SEX',hue='default.payment.next.month',data = df)
# 设置x轴不同标签名称
ax.set_xticklabels(['男', '女'],fontsize=12)
# 设置x轴名称
plt.xlabel("性别")
plt.ylabel("")
# 设置图的标题
plt.title('不同性别违约情况')plt.subplot(1,3,2)
ax=sns.countplot(x='EDUCATION',hue='default.payment.next.month',data = df)
ax.set_xticklabels(['其他', '高中','本科','研究生及以上'],fontsize=12)
plt.xlabel("教育程度")
plt.ylabel("")
plt.title('不同教育程度违约情况')plt.subplot(1,3,3)
ax=sns.countplot(x='MARRIAGE',hue='default.payment.next.month',data = df)
ax.set_xticklabels(['其他', '已婚','未婚'], fontsize=12)
plt.xlabel("婚姻状况")
plt.ylabel("")
plt.title('不同婚姻状况违约情况')plt.show()


从图中可以看出,虽然男性的数量远低于女性,但违约人数并没有明显低于女性违约人数。对于婚姻状况也存在类似情况,未婚的人数比已婚人数多,但违约人数和已婚的违约人数相差无几,也说明了未婚人数的违约概率可能要大一些。

我们再考察对于年龄和信用卡额度的违约情况。

t0 = df[df['default.payment.next.month'] == 0]   # 未违约的样本数据
t1 = df[df['default.payment.next.month'] == 1]   # 违约的样本数据
plt.figure()
fig, ax = plt.subplots(1,2,figsize=(12,6))# 画第一个子图
plt.subplot(1,2,1)
# 画直方图,设置高斯核密度估计图参数,以字典传入核密度图的属性信息
sns.distplot(t0['AGE'],kde_kws={"color":"blue","label":"未违约"})
sns.distplot(t1['AGE'],kde_kws={"color":"orange","label":"违约"})
# 设置x轴名称、字符大小
plt.xlabel('年龄', fontsize=12)
locs, labels = plt.xticks()
plt.title('不同年龄违约情况')
# 刻度线参数设置
plt.tick_params(axis='both', which='major', labelsize=12)plt.subplot(1,2,2)
sns.distplot(t0["LIMIT_BAL"],kde_kws={"color":"blue","label":"未违约"})
sns.distplot(t1["LIMIT_BAL"],kde_kws={"color":"orange","label":"违约"})
plt.xlabel('信用卡额度', fontsize=12)
locs, labels = plt.xticks()
plt.title('不同信用卡额度违约情况')
plt.tick_params(axis='both', which='major', labelsize=12)plt.show()


仔细观察上图,我们可以获取更多有趣的信息。例如30岁前,客户的违约概率更大;30-40岁之间是客户信用最高的区间,40岁之后再次下降;信用卡额度较低的客户违约概率更高。

3 分类建模

我们首先尝试使用一些基本的机器学习模型对数据直接进行分类建模,并给出分类的预测结果。我们选用比较经典的KNN和决策树来观察效果。

3.1 KNN模型

在KNN模型中,由于要计算欧氏距离,因此应该先对离散变量做哑变量编码处理,使其变为数值型特征
我们对无序离散变量SEX,MARRIAGE进行哑变量编码。

str_columns = ['SEX','MARRIAGE']
df_new = pd.get_dummies(df, columns=str_columns)
y = df_new['default.payment.next.month']  #因变量
X = df_new.drop(columns=['ID','default.payment.next.month']) #去除因变量与ID,剩余为特征

数值型的变量的各指标相差很大时,如果直接使用原始值计算,就会突出数值较大的指标在分析中的作用、削弱数值较小的指标在分析中的作用,所以要进行特征缩放。

对特征列进行标准化处理,使得处理过后的每一列数据都是均值为0,标准差为1的数据。

X.iloc[:,0:21] = preprocessing.scale(X.iloc[:,0:21])

划分数据集。

X_train, X_test,y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

下面,我们使用sklearn中的KNeighborsClassifier对训练集进行分类训练。当不输入参数时,默认KNN所选取的n_neighbors参数取值为5。

# 创建knn类
knn_model = KNeighborsClassifier()
# 对数据进行拟合学习
knn_model.fit(X_train, y_train)

得到模型knn_model后,我们在测试集上验证其分类效果
用predict方法获取模型对每一个测试集样本标签的预测结果knn_pred
用predict_proba方法获取模型把每一个样本划分为正类的概率knn_score

# 预测结果
knn_pred = knn_model.predict(X_test)
# 属于正类的概率
knn_score = knn_model.predict_proba(X_test)[:,1]

为了展示分类模型的效果,我们需要获取模型的准确率得分,分类报告以及混淆矩阵。
sklearn中的accuracy_score用于计算准确率
sklearn中的classification_report函数用于显示主要分类指标的文本报告.在报告中显示每个类的精确度,召回率,F1值等信息
sklearn中的confusion_matrix总结模型真实值与预测值的情形分析表,以矩阵形式显示

为了方便后续使用,我们定义一个函数Get_report来获取这些信息。

Get_report(y_test , knn_pred)

模型的准确率为:0.7915555555555556
模型的分类报告展示如下:
precision recall f1-score support

       0       0.84      0.91      0.87      70601       0.53      0.35      0.42      1940accuracy                           0.79      9000

macro avg 0.68 0.63 0.64 9000
weighted avg 0.77 0.79 0.77 9000

模型的混淆矩阵展示如下:
我们发现,虽然总体预测的精准度尚可,违约样本的实际召回率只有0.27,能够综合展示正类样本的准确率和召回率的f1-score只有0.36。我们再尝试其他模型进行对比。

3.2 决策树

引入决策树算法,直接进行模型训练,并展示模型训练结果,与KNN得到的结果进行对比。

from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
tree_model = DecisionTreeClassifier(random_state=1)
tree_model.fit(X_train, y_train)
tree_score = tree_model.predict_proba(X_test)[:,1]
tree_pred = tree_model.predict(X_test)
Get_report(y_test,tree_pred)

模型的准确率为:0.7307777777777777
模型的分类报告展示如下:
precision recall f1-score support

       0       0.84      0.82      0.83      70601       0.39      0.42      0.40      1940accuracy                           0.73      9000

macro avg 0.61 0.62 0.61 9000
weighted avg 0.74 0.73 0.74 9000

模型的混淆矩阵展示如下:

4 数据过采样

在使用KNN算法和决策树算法后,我们得到的训练结果均较为一般,我们重新回顾之前得到的结论:这个样本是一个存在类别不平衡问题的样本。

from imblearn.over_sampling import SMOTE
# 划分数据集
X_train, X_test,\
y_train, y_test \
= train_test_split(X, y, test_size=0.3, random_state=0)
# 定义一个SMOTE模型
smo = SMOTE(random_state=42)
# fit_resample拟合数据
X_smo, y_smo = smo.fit_resample(X_train, y_train)
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
tree_model = DecisionTreeClassifier(random_state=1)
tree_model.fit(X_smo, y_smo)
tree_score = tree_model.predict_proba(X_test)[:,1]
tree_pred = tree_model.predict(X_test)
Get_report(y_test,tree_pred)

5 引入新评价指标

同时,针对不平衡样本的评价指标也需要进行相应的更新,我们可以引入Precision_Recall_curve、AP值、ROC_curve、G-mean

我们定一个Get_curve函数,展示这些曲线,并给出一系列对应的数值。

6 集成学习

下面我们引入一种强力的算法-XGBoost,作为Boosting的代表之一,它是对GBDT(Gradient Boosting Decision Tree)的一种改进,我们在对数据进行重采样后进行学习。

6.1 XGBoost

# 划分数据集
X_train, X_test,\
y_train, y_test \
= train_test_split(X, y, test_size=0.3, random_state=0)# 过采样处理
smo = SMOTE(random_state=42)
X_smo, y_smo = smo.fit_resample(X_train, y_train)
from xgboost import XGBClassifier
model = XGBClassifier(booster='gbtree',learning_rate=0.1,gamma=1,scale_pos_weight=1,n_estimators=1000,max_depth=6,alpha=5,reg_lambda=1)
# 设置训练数据
eval_set = [(X_test, y_test)]
model.fit(X_smo, y_smo, early_stopping_rounds=10, eval_metric="auc", eval_set=eval_set, verbose=False)
y_pred = model.predict(X_test)
y_socre = model.predict_proba(X_test)[:,1]
# predictions = [round(value) for value in y_pred]
Get_curve(y_test,y_socre,y_pred)


AP值:0.5284780662232265
F1最大对应阈值 = 0.49564602971076965
Gmean最大对应阈值 = 0.4803217351436615
准确率得分= 0.7938888888888889
最大Gmean = 0.7028493826938129
最大F1 = 0.5300546448087432

6.2 CATBOOST

我们最后再使用一种在处理类别特征时通常效果更好的算法:CatBoost。它的基本原理类似于常规的Gradient Boosting算法,它一方面可以自动处理分类特征

由于可以自动处理分类特征,我们可以直接使用未进行哑变量编码的数据进行计算。

y = df['default.payment.next.month'] # 因变量
X = df.drop(columns=['ID','default.payment.next.month']) # 去除ID与因变量,剩余为特征
X_train, X_test,\
y_train, y_test \
= train_test_split(X, y, test_size=0.3, random_state=0)
from sklearn.model_selection import GridSearchCV
from catboost import CatBoostClassifiercategorical_features_indices = ['SEX','MARRIAGE']
model = CatBoostClassifier(iterations=100, depth=6, cat_features = categorical_features_indices, loss_function='Logloss', logging_level='Silent')
model.fit(X_train,y_train,eval_set=(X_test, y_test))
cb_pred = model.predict(X_test)
cb_socre = model.predict_proba(X_test)[:,1]
# predictions = [round(value) for value in cb_pred]
Get_curve(y_test, cb_socre, cb_pred)


AP值:0.5496398051016296
F1最大对应阈值 = 0.2518803714670295
Gmean最大对应阈值 = 0.21489477235998308
准确率得分= 0.8255555555555556
最大Gmean = 0.7112365138132554
最大F1 = 0.5477949940405245

综合来看,CatBoost取得了较好的效果,但我们发现G-mean的最大值和F1的最大值并不能同时取到,二者之间存在取舍关系,在处理实际问题时,需要根据对正类样本的分类需求来决定。是更加追求正类样本的召回率,还是整体判别的精确性?此处我们分别给出G-mean最大时的模型和F1最大时的模型,仅供参考。

THRESHOLD = 0.2518803714670295
# 大于阈值输出1,小于则输出0
y_pred = np.where(model.predict_proba(X_test)[:,1] >= THRESHOLD, 1, 0)
Get_report(y_test,y_pred)

模型的准确率为:0.7892222222222223
模型的分类报告展示如下:
precision recall f1-score support

       0       0.88      0.84      0.86      70601       0.51      0.59      0.55      1940accuracy                           0.79      9000

macro avg 0.70 0.72 0.71 9000
weighted avg 0.80 0.79 0.79 9000
这是追求F1最大时的效果,此时设置分类阈值为0.2518803714670295 , F1值达到了0.55。

THRESHOLD = 0.21489477235998308
# 大于阈值输出1,小于则输出0
y_pred = np.where(model.predict_proba(X_test)[:,1] >= THRESHOLD, 1, 0)
Get_report(y_test,y_pred)

模型的准确率为:0.7566666666666667
模型的分类报告展示如下:
precision recall f1-score support

       0       0.89      0.79      0.84      70601       0.45      0.64      0.53      1940accuracy                           0.76      9000

macro avg 0.67 0.71 0.68 9000
weighted avg 0.80 0.76 0.77 9000

这是追求Gmeans最大时的效果,此时设置分类阈值为0.21489477235998308,F1值有一定的下降,但是正类样本的召回率达到了0.64。根据实际问题的不同需求,两种结果具有不同的实际意义。例如,如果我们认为放过违约样本的代价较大,我们可以选择以Gmeans最大化作为算法的评价指标。

7 结论

对于不平衡样本的分类问题,直接使用机器学习模型并非能得到很好的效果,重采样是可能能够提升模型训练效果的办法。本案例一共使用了六种不同的分类模型算法,其中CatBoost实现了最好的分类效果。

台湾地区信用卡客户贷款违约预测相关推荐

  1. python信用卡违约预测分析_Python作业集:信用卡还款违约预测

    Part 1 数据集和数据字典 数据集包含某银行信用卡部门4月至6月违约信息,人口信息,信用额度,还款状况,还款金额,历史账单,任务是用模型预测用户的违约情况.(https://www.kaggle. ...

  2. Bank Credit_个人贷款违约预测

    # 本次case主题:个人贷款违约预测模型# 本案例使用一套真实的数据集演示贷款违约预测模型开发的全流程.这个流程就是数据挖掘项目的分析思路的直接体现,如下: # 一.数据介绍# 本案例所用数据来自一 ...

  3. Kaggle债务违约预测冠军经验分享

    版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 引言 SWOT分析法 优势Strengths利用我们已有的优势 弱势weaknesses我们需要提升的领域 机会opportun ...

  4. 基于机器学习与深度学习的金融风控贷款违约预测

    基于机器学习与深度学习的金融风控贷款违约预测 目录 一.赛题分析 1. 任务分析 2. 数据属性 3. 评价指标 4. 问题归类 5. 整体思路 二.数据可视化分析 1. 总体数据分析 2. 数值型数 ...

  5. 笔记之零基础入门金融风控-贷款违约预测

    零基础入门金融风控-贷款违约预测 赛题描述 赛题概况 数据概况 合理的创建标题,有助于目录的生成 预测指标 赛题流程 评分卡 笔记记录转载 赛题描述 赛题以金融风控中的个人信贷为背景,要求选手根据贷款 ...

  6. 零基础入门金融风控之贷款违约预测挑战赛-task01

    零基础入门金融风控之贷款违约预测挑战赛-task01 零基础入门金融风控之贷款违约预测挑战赛 1.赛题描述 根据某信贷平台的贷款记录的数据,进行训练测试,预测用户贷款是否违约,得出用户违约的概率. 在 ...

  7. 「机器学习」天池比赛:金融风控贷款违约预测

    一.前言 1.1 赛题背景 赛题以金融风控中的个人信贷为背景,要求选手根据贷款申请人的数据信息预测其是否有违约的可能,以此判断是否通过此项贷款,这是一个典型的分类问题. 任务:预测用户贷款是否违约 比 ...

  8. DataWhale天池-金融风控贷款违约预测-Task01赛题理解

    目录 一.赛题概况 二.数据集介绍 三.预测指标 理解 通过ROC曲线评估分类器 最佳阈值点选择 一.赛题概况 本次新人赛是Datawhale与天池联合发起的0基础入门系列赛事第四场 -- 零基础入门 ...

  9. 零基础入门金融风控-贷款违约预测-机器学习-数据分析

    零基础入门金融风控-贷款违约预测 一.赛题数据 赛题以预测用户贷款是否违约为任务,数据集报名后可见并可下载,该数据来自某信贷平台的贷款记录,总数据量超过120w,包含47列变量信息,其中15列为匿名变 ...

最新文章

  1. 设置树莓派的无线网卡为监听模式(monitor)
  2. Android消息机制 Looper源码阅读
  3. 不能使用 '';文件已在使用中。
  4. 通过一个具体的例子学习Threadlocal Test
  5. python图片重命名 工具_python - 请问django如何给上传的图片重命名
  6. Google SSL zz
  7. 策划反推文档教程:格式篇
  8. 1032. Sharing (25)
  9. EasyRecovery15绿色版免安装数据恢复软件
  10. Unity 导入原神人物模型
  11. 大数据精准营销数据分析处理(一)
  12. 前沿探索:腾讯云数据库自治服务最佳实现
  13. 计计算机专用英语(常用1695个单词,带音标) 欢迎评论转发
  14. Accelerated Proximal Gradient Method/FISTA
  15. poj 2044 weather forcast
  16. Java指导书练习题——抽象类
  17. vue下拉el-select二级联动
  18. 【超级简单】向量范数计算
  19. python数据去重_python 大数据去重
  20. ibm服务器怎么安装win7系统安装,thinkpad如何安装win7系统

热门文章

  1. ug专属界面如何定制,ug软件如何定制角色
  2. 同创永益CTO郑阳受邀在清华MEM大讲堂分享“混沌工程在复杂业务稳定性中的应用”
  3. eNSP配置DHCP服务器
  4. uniapp 电商app 步骤条功能的使用
  5. 5G/NR PRACH和preamble如何与SSB进行映射?
  6. 全排列邻位对换法c语言算法,全排列——邻位对换法
  7. 波士顿动力机器人解锁跑酷新技能,凭借感知驱动技术适应技能
  8. SQL之exists、not exists
  9. [Java基础 持久层Mybatis] Mybatis使用IN语句查询
  10. 3dmax uv贴图方法大全