欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > 【机器学习与数据挖掘实战】案例04:基于K-Means算法的信用卡高风险客户识别

【机器学习与数据挖掘实战】案例04:基于K-Means算法的信用卡高风险客户识别

2025/2/25 22:23:31 来源:https://blog.csdn.net/Morse_Chen/article/details/144504897  浏览:    关键词:【机器学习与数据挖掘实战】案例04:基于K-Means算法的信用卡高风险客户识别

在这里插入图片描述

【作者主页】Francek Chen
【专栏介绍】 ⌈ ⌈ 机器学习与数据挖掘实战 ⌋ ⌋ 机器学习是人工智能的一个分支,专注于让计算机系统通过数据学习和改进。它利用统计和计算方法,使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数据集中发现模式、关联和异常的过程,旨在提取有价值的信息和知识。机器学习为数据挖掘提供了强大的分析工具,而数据挖掘则是机器学习应用的重要领域,两者相辅相成,共同推动数据科学的发展。本专栏介绍机器学习与数据挖掘的相关实战案例。
【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/ML-DM_cases。

文章目录

    • 一、目标分析
      • (一)背景
      • (二)数据说明
      • (三)分析目标
    • 二、数据探索
    • 三、数据预处理
      • (一)数据清洗
      • (二)属性构建
    • 四、分析与建模
      • (一)聚类参数寻优
      • (二)构建信用卡高风险客户识别模型
      • (三)信用卡客户风险分析
    • 五、模型评价
    • 小结


一、目标分析

(一)背景

1. 信用卡的定义

信用卡是银行或其他财务机构签发给那些资信状况良好的人士,用于在指定的商家购物和消费,或在指定银行机构存取现金的特制卡片,是一种特殊的信用凭证。

在这里插入图片描述

2. 信用卡的分类

随着信用卡业务的发展,信用卡种类不断增多,一般有广义信用卡和狭义信用卡之分。

  • 广义信用卡:是指凡是能够为持卡人提供信用证明、消费信贷或持卡人可凭卡购物、消费或享受特定服务的特制卡片,包括贷记卡、准贷记卡、借记卡、储蓄卡、提款卡(ATM 卡)、支票卡及赊账卡等。
  • 狭义信用卡:是指由银行或其他财务机构发行的贷记卡,即无需预先存款就可以贷款消费的信用卡,是先消费后还款的信用卡。(注:本案例所讨论的信用卡,主要指狭义上的信用卡,即“贷记卡”。)

3. 信用卡的功能和实质

功能:包括支付结算、转账结算、消费贷款、循环授信和提取现金。其中,消费贷款是信用卡最重要的功能,改变了传统的消费支付方式,扩大了社会的信用规模,促进了社会的消费需求。

实质:循环消费信贷的新型支付工具。

4. 信用卡支付与传统支付

在这里插入图片描述

5. 信用卡的产生和发展

某地区的信用卡产业始于20世纪80年代,1989年开始向外资银行开放市场后,以花旗银行、汇丰银行、美国运通为代表的信用卡巨头依托成熟的信用卡业务模式,依托合理风险下的经营理念,特别是开创了信用卡销售外包模式,迅速占领了某地区信用卡市场。发卡量从1989年的50多万张一跃到1995年的500多万张。90年代中后期,以中国信托银行、台新银行等银行开始在信用卡业务上发力,以犀利的市场营销战略重新夺得信用卡市场。

在这里插入图片描述

为了推进信用卡业务良性发展,减少坏账风险,各大银行都进行了信用卡客户风险识别相关工作,建立了相应的客户风险识别模型。某银行因旧的风险识别模型随时间推移,很难适应业务发展需求,需要重新进行风险识别模型构建。对不同客户类别进行特征分析,比较不同客户的风险。评估该机构的信用卡业务风险,针对目前的情况提出风控建议。

在这里插入图片描述

(二)数据说明

属性名称属性取值说明示例
顾客编号CDMS0000001
申请书来源1.Take-One邮寄件 2.现场办卡 3.电访 4.亲签亲访 5.亲访 6.亲签 7.本行VIP、PB 8.其他1
瑕疵户1.是 2.否2
逾期1.是 2.否1
呆账1.是 2.否2
借款余额1.是 2.否1
退票1.是 2.否2
拒往记录1.是 2.否1
强制停卡记录1.是 2.否2
频率1.天天用 2.经常用 3.偶而用 4.很少用 5.没有用2
个人月收入1.无收入 2.10000元以下 3.10001-20000元 4.20001-30000元 5.30001-40000元 6.40001-50000元 7.50001-60000元 8.60001元以上4
个人月开销1.10000元以下 2.10001-20000元 3.20001-30000元 4.30001-40000元 5.40001元以上5
家庭月收入1.20000元以下 2.20001-40000元 3.40001-60000元 4.60001-80000元 5.80001-100000元 6.100001元以上3
月刷卡额1.20000元以下 2.20001-40000元 3.40001-60000元 4.60001-80000元 5.80001-100000元 6.100001-150000元 7.150001-200000元 8.200000以上4
人口数1.1人 2.2人 3.3人 4.4人 5.5人 6.6人 7.7人 8.8人 9.9人以上2
家庭经济1.上 2.中上 3.中 4.中下 5.下1
都市化程度1.都会 2.都市 3.城镇2
张数1.1张 2.2张 3.3张 4.4张 5.大于4张5
学历1.小学及以下 2.国初中 3.高中职 4.专科 5.大学及以上2
职业1.管理职 2.专门职 3.技术职 4.事务职 5.销售职 6.劳务职 7.服务职 8.农林渔牧自营 9.商工服务自营(员工9人以下) 10.自由业自营 11.经营者(员工10人以上) 12.家庭主妇(没有兼副业) 13.家庭主妇(有兼副业) 14.无职 15.其他3
住家1.租赁 2.宿舍 3.本人所有 4.父母所有 5.配偶所有 6.其他2
户籍1.北部 2.中部 3.南部 4.东部3
性别1.女 2.男1
宗教信仰1.宗教1 2.宗教2 3.宗教3 4.宗教4 5.宗教5 6.宗教6 7.其他2
年龄1.此信用卡持有人之15-19岁 2.20-24岁 3.25-29岁 4.30-34岁 5.35-39岁 6.40-44岁 7.45-49岁 8.50-54岁 9.55-59岁5
婚姻1.未婚 2.已婚 3.其他1
血型1.A型 2.B型 3.AB型 4.O型1
星座1.白羊座 2.金牛座 3.双子座 4.巨蟹座 5.狮子座 6.处女座 7.天秤座 8.天蝎座 9.射手座 10.魔羯座 11.双鱼座1

(三)分析目标

结合信用卡高风险客户识别的数据情况,利用K-Means聚类模型,可以实现以下目标。

  • 识别出哪些客户为高风险类客户,哪些客户为禁入类客户。
  • 对不同客户类别进行特征分析,比较不同客户的风险。
  • 评估该机构的信用卡业务风险,针对目前的情况提出风控建议。

信用卡高风险客户识别数据挖掘主要步骤如下。

  1. 了解不同客户类别的特征背景、数据说明和分析目标。
  2. 分析客户历史信用记录、经济情况、经济风险情况,对不同客户类别进行数据探索。
  3. 对数据定义冲突数据进行数据清洗、属性构造。
  4. 构建K-Means聚类模型,对信用卡客户进行风险分析。
  5. 根据构建后的模型结果进行模型评价。
  6. 根据聚类模型得到的客户风险分类结果提出风控建议。

在这里插入图片描述

二、数据探索

1. 描述性统计分析

描述性统计分析的本质是对数据概况的了解,进行描述性统计分析不仅能检查数据是否存在质量问题,而且也有助于之后数据特征信息的选取。对信用卡信息数据进行描述性统计分析,得到部分描述性统计结果如下表。

# 描述性统计分析
import pandas as pd# 读取数据文件
credit = pd.read_csv('../data/credit_card.csv', encoding='GBK')
# 删除信用卡顾客编号属性
credit = credit.drop('信用卡顾客编号', axis=1)
length = len(credit)  # 计算数据量
# 定义描述性统计函数,且将结果保留3位小数
def status(x): return pd.Series([x.count(), length - x.count(), len(credit.groupby(by=x)), x.max() - x.min(),x.quantile(.75) - x.quantile(.25), x.mode()[0], format(x.var(), '.3f'), format(x.skew(), '.3f'), format(x.kurt(), '.3f')], index=['非空值数', '缺失值数','类别数', '极差', '四分位差', '众数', '方差', '偏度', '峰度'])# 应用描述性统计函数
describe_tb = credit.apply(status)
describe_tb

在这里插入图片描述

2. 客户历史信用记录与瑕疵户的关系

凡有迟缴,逾期,呆账,退票,停卡,银行拒往,保证人信用不良,配偶信用不良者,均属信用瑕疵范围。查看瑕疵户在客户中分布并绘制柱形图。瑕疵户在客户中分布所占比例较少。

根据瑕疵户的定义,查看逾期、呆账、强制停卡记录、退票记录和拒往记录5个历史信用记录情况在瑕疵户中的占比。

import matplotlib.pyplot as plt
from collections import OrderedDict
plt.rcParams['font.family'] = 'SimHei'  # 正常显示中文plt.figure(figsize=(5, 4))  # 设置画布大小
plt.bar(['是'], credit['瑕疵户'].value_counts()[1], color='r', width=0.3)
plt.bar(['否'], credit['瑕疵户'].value_counts()[2], color='b', width=0.3)
plt.ylabel('客户数量', fontsize=12)  # 设置y轴坐标和字体大小
plt.title('瑕疵户', fontsize=12)  # 设置标题和字体大小
plt.show()# 编写瑕疵户与信用记录之间的关系函数
def credit_plot(column, i):ax = plt.subplot(3, 2, i)  # 子画布is_data = credit[credit['瑕疵户'] == 1][column]  # 瑕疵户数据not_data = credit[credit['瑕疵户'] == 2][column]  # 非瑕疵户数据is_y = is_data.value_counts() / is_data.shape[0]  # y数据ax.bar(1, is_y[1], color='r', label='是', width=0.3)  # 绘制柱状图if len(is_y) == 2:ax.bar(1, is_y[2], bottom=is_y[1], color='b', width=0.3)  # 柱堆叠not_y = not_data.value_counts() / not_data.shape[0]  # y数据ax.bar(2, not_y[1], color='r', width=0.3)  # 绘制柱形图ax.bar(2, not_y[2], bottom=not_y[1], color='b', label='否', width=0.3)  # 绘制柱形图ax.set_xticks([1, 2])  # 设置x轴坐标ax.set_xticklabels(['是', '否'], fontsize=14)  # 设置x轴坐标标签plt.ylabel('占比', fontsize=14)  # 设置y标题plt.title(column, fontsize=14)  # 设置标题plt.tight_layout(1.5)  # 调整子图间距
plt.figure(figsize=(9, 9))  # 设置画布大小# 绘制瑕疵户与信用记录关系图
credit_plot('逾期', 1)
credit_plot('呆账', 2)
credit_plot('强制停卡记录', 3)
credit_plot('退票', 4)
credit_plot('拒往记录', 5)
plt.legend(loc=[2.3, 3.3], fontsize=12, handlelength=1)  # 添加图例
plt.show()

在这里插入图片描述
在这里插入图片描述

3. 客户经济情况

判断客户是否为高风险客户,不仅要分析客户的历史信用记录,还要考虑客户现有的经济情况及还款能力,因此分析客户的个人月开销、月刷卡额、个人月收入和家庭月收入等属性。

# 定义绘制客户经济情况分析直方图的函数
def economic_plot(column, tick, a): ax = plt.subplot(2, 2, a)  # 子图situ = sorted(credit[column].unique())  # 排序x = [i for i in range(len(situ))]  # x轴坐标数据y = [credit[column].value_counts()[i] for i in situ]  # y轴数据ax.bar(x, y, width=0.3)  # 绘制柱状图plt.ylabel('数量', fontsize=14)  # y轴坐标轴标题plt.xticks(rotation=30)  # x轴坐标轴标签倾斜程度ax.set_xticks([i for i in range(len(x))])  # 重设x轴坐标数据   ax.set_xticklabels(tick, fontsize=14)  # 设置x轴显示坐标数据ax.set_xlabel(column+'(万元)', fontsize=14)  # y轴坐标轴标题plt.tight_layout(3)  # 控制子图之间的距离
plt.figure(figsize=(10, 8))# 设置x轴坐标
tick1 = ['1以下', '1~2', '2~3', '3~4', '4以上']  # 个人月开销
tick2 = ['2以下', '2~4', '4~6', '6~8', '8~10', '10~15', '15~20', '20以上']  # 月刷卡额
tick3 = ['无收入', '0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6以上']  # 个人月收入
tick4 = ['未知', '2以下', '2~4', '4~6', '6~8', '8~10', '10以上']  # 家庭月收入
economic_plot('个人月开销', tick1, 1)
economic_plot('月刷卡额', tick2, 2)
economic_plot('个人月收入', tick3, 3)
economic_plot('家庭月收入', tick4, 4)
plt.show()

在这里插入图片描述

观察图可以发现家庭月收入有一个未知具体意义的属性值0。

4. 客户经济风险

自定义包color.py的代码如下:

import colorsys
import randomdef get_n_hls_colors(num):hls_colors = []i = 0step = 360.0 / numwhile i < 360:h = is = 90 + random.random() * 10l = 50 + random.random() * 10_hlsc = [h / 360.0, l / 100.0, s / 100.0]hls_colors.append(_hlsc)i += stepreturn hls_colorsdef ncolors(num):rgb_colors = []if num < 1:return rgb_colorshls_colors = get_n_hls_colors(num)for hlsc in hls_colors:_r, _g, _b = colorsys.hls_to_rgb(hlsc[0], hlsc[1], hlsc[2])r, g, b = [int(x * 255.0) for x in (_r, _g, _b)]rgb_colors.append([r, g, b])return rgb_colorsdef color(value):digit = list(map(str, range(10))) + list("ABCDEF")if isinstance(value, tuple):string = '#'for i in value:a1 = i // 16a2 = i % 16string += digit[a1] + digit[a2]return stringelif isinstance(value, str):a1 = digit.index(value[1]) * 16 + digit.index(value[2])a2 = digit.index(value[3]) * 16 + digit.index(value[4])a3 = digit.index(value[5]) * 16 + digit.index(value[6])return (a1, a2, a3)
# 导入自行编写的绘制指定数量颜色的函数
from color import color, ncolors# 编写个人月收入,家庭月收入与月刷卡额之间的关系函数
def risk_plot(column1, column2, xlabel_list=[], ylabel_list=[]):fig, ax = plt.subplots(figsize=(8, 6))  # 画布大小x_data = credit[column1]  # x轴数据co = list(map(lambda x:color(tuple(x)), ncolors(len(ylabel_list))))  # 指定数量的颜色# 循环绘制柱状堆叠图for i in sorted(x_data.unique()):y_data = credit[x_data == i][column2]       part = sorted(y_data.unique())exp = 0if part[0] == 0:for j in part:exp1 = y_data.value_counts()[j] / len(y_data)ax.bar(i, exp1, bottom=exp, width=0.5, color=co[j], label=ylabel_list[j])exp += exp1 else:for j in part:exp1 = y_data.value_counts()[j] / len(y_data)ax.bar(i, exp1, bottom=exp, width=0.5, color=co[j-1], label=ylabel_list[j-1])exp += exp1     ax.set_xticks([i+1 for i in range(len(x_data.unique()))])  # 重设x轴坐标数据ax.set_xticklabels(xlabel_list, fontsize=10)  # 设置x轴坐标显示数据ax.set_xlabel(column1 + '(万元)', fontsize=10)  # 设置x轴标题plt.ylabel('占比', fontsize=12)  # 设置y轴标题# 图例去重handles, labels = plt.gca().get_legend_handles_labels()  by_label = OrderedDict(zip(labels, handles))plt.legend(by_label.values(), by_label.keys(), loc=[1.01, 0], fontsize=10, title=column2+'(万元)')# 调整子图位置fig.subplots_adjust(right=0.8)
print('\n')    
risk_plot('个人月收入', '家庭月收入', ['无收入', '0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6以上'], ['未知', '2以下', '2~4', '4~6', '6~8', '8~10', '10以上'])
plt.show()
risk_plot('月刷卡额', '个人月收入', ['2以下', '2~4', '4~6', '6~8', '8~10', '10~15', '15~20', '20以上'], ['无收入', '0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6以上'])
plt.show()
risk_plot('月刷卡额', '家庭月收入', ['2以下', '2~4', '4~6', '6~8', '8~10', '10~15', '15~20', '20以上'], ['未知', '2以下', '2~4', '4~6', '6~8', '8~10', '10以上'])
plt.show()

(1)个人月收入与家庭月收入的关系

个人月收入基本小于等于家庭月收入,且当个人月收入分别为3~4万元,4~5万元时,家庭月收入所对应的分别8~10万元及10万以上,而未知属性所对应的个人月收入为5~6万以及6万以上。

在这里插入图片描述

(2)月刷卡额与个人月收入的关系

客户的月刷卡额普遍大于个人月收入。

在这里插入图片描述

(3)月刷卡额与家庭月收入的关系

客户的月刷卡额甚至大于家庭月收入,因此客户的经济风险也属于高风险客户的范畴之一。

在这里插入图片描述

三、数据预处理

(一)数据清洗

根据变量定义,删除不符合定义的记录。

变量名定义
瑕疵户凡有迟缴,逾期,呆账,退票,停卡,银行拒往,保证人信用不良,配偶信用不良者,均属瑕疵范围
逾期此信用卡是否在本行逾期超过30天
呆账已过偿付期限,经催讨尚不能回收,长期处于呆滞状态,有可能成为坏账的款项
强制停卡信用卡若超过三个月没有缴款,银行会将您的信用卡停止使用,在停卡前会先经过催收等过程。
退票开票人在一定时间内无法将钱存入账户中,银行视为退票。
拒往记录信用记录不好,有退票记录,停卡记录,呆账记录,均会被银行拒绝往来。

查看数据属性,发现频率属性存在“不使用”这一取值,所以对应的刷卡额应该在20000以下,对于刷卡额超过两万的数据,则视为异常数据,应予以删除。

# 数据清洗
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
carddata = pd.read_csv('../data/credit_card.csv', engine='python')# 筛选逾期但是不是瑕疵户的数据
exp1 = (carddata['逾期'] == 1) & (carddata['瑕疵户'] == 2)  
# 筛选呆账但是不是瑕疵户的数据
exp2 = (carddata['呆账'] == 1) & (carddata['瑕疵户'] == 2) 
# 筛选有强制停卡记录但是不是瑕疵户的数据
exp3 = (carddata['强制停卡记录'] == 1) & (carddata['瑕疵户'] == 2) 
# 筛选退票但是不是瑕疵户的数据
exp4 = (carddata['退票'] == 1) & (carddata['瑕疵户'] == 2) 
# 筛选有拒收记录但是不是瑕疵户的数据
exp5 = (carddata['拒往记录'] == 1) & (carddata['瑕疵户'] == 2) 
# 筛选有呆账但是没有拒收记录的数据
exp6 = (carddata['呆账'] == 1) & (carddata['拒往记录'] == 2) 
# 筛选有强制停卡记录但是没有拒收记录的数据
exp7 = (carddata['强制停卡记录'] == 1) & (carddata['拒往记录'] == 2)
# 筛选退票但是没有拒收记录的数据
exp8 = (carddata['退票'] == 1) & (carddata['拒往记录'] == 2) 
# 筛选频率为5但是月刷卡额大于1的数据
exp9 = (carddata['频率'] == 5) & (carddata['月刷卡额'] > 1) 
# 筛选异常数据
Final = carddata.loc[(exp1 | exp2 | exp3 | exp4 | exp5 | exp6 | exp7 | exp8 | exp9).apply(lambda x:not(x)), :]
Final.reset_index(inplace = True)
Final

在这里插入图片描述

家庭月收入存在为“未知”的情况,而在数据说明表中并未有指出其家庭月收入的范围。考虑家庭月收入和个人月收入存在一定的相关关系,经过探索发现家庭月收入为5、6的客户与个人月收入为5、6的客户存在一一对应的关系。同时个人月收入7、8对应的家庭月收入正是未知。鉴于此,求出个人月收入为5和6的客户的个人月收入占家庭月收入的比值,从而根据这个比值求出家庭月收入为未知的客户的家庭月收入等级。经求取得出家庭月收入在15万元~19万元之间,因此将家庭月收入未知的等级更改为6。

# 个人月收入(万元)
PersonalMonthIncome = [0, 1, 2, 3, 4, 5, 6, 7, 8]
for i in range(8):Final.loc[Final['个人月收入'] == i + 1, '个人月收入'] = PersonalMonthIncome[i]
# 根据5 、6的情况计算个人月收入和家庭月收入的比值,确定家庭月收入为未知的情况
FamilyMonthIncome = [2, 4, 6, 8, 10, 12]
m = (Final.loc[: , '家庭月收入'] == 5)
Final.loc[m, '家庭月收入'] = FamilyMonthIncome[4]
ratio5 = Final.loc[m, '个人月收入'] / Final.loc[m, '家庭月收入']
m1 = Final.loc[: , '家庭月收入'] == 6
Final.loc[m1, '家庭月收入'] = FamilyMonthIncome[5]
ratio6 = Final.loc[m1, '个人月收入'] / Final.loc[m1, '家庭月收入']# 家庭月收入(万元)
FamilyMonthIncome = [2, 4, 6, 8, 10, 15]
Final.loc[Final['家庭月收入'] == 0, '家庭月收入'] = 6
for i in range(6):m2 = Final.loc[: , '家庭月收入'] == i + 1Final.loc[m2, '家庭月收入'] = FamilyMonthIncome[i]# 月刷卡额(万元)
MonthCardPay = [2, 4, 6, 8, 10, 15, 20, 25]
for i in range(8):m = Final.loc[: , '月刷卡额'] == i + 1Final.loc[m, '月刷卡额'] = MonthCardPay[i]# 个人月开销(万元)
PersonalMonthOutcome = [1, 2, 3, 4, 6]
for i in range(5):m = Final['个人月开销'] == i + 1Final.loc[m, '个人月开销'] = PersonalMonthOutcome[i]

因为属性个人月收入、个人月开销、家庭月收入、月刷卡额的范围不相同,区间大小不统一,对后期进行运算带来了诸多不便,故将属性的单位统一为“万元”,取每个区间的最大值代表这个区间。

(二)属性构建

在信用卡相关的征信工作中,主要从“历史信用,经济状况,收入稳定情况”三个方向判定客户的信用等级,他们所包含的变量如下。

历史信用经济状况收入稳定情况
呆账个人月收入住家
瑕疵户家庭月收入职业
逾期月刷卡额年龄
强制停卡记录个人月开销
退票借款余额
拒往记录

对这3个方向所包含的变量进行打分,并赋予相应的权重,得到相加后的总分,得分越高,则风险越高。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

相关代码如下。

# 属性值为1(是)的记为1分,属性值为2(否)的记为0分
def GetScore(x):if x == 2 :a = 0else:a = 1return(a)BuguserSocre = Final['瑕疵户'].apply(GetScore)
OverdueScore = Final['逾期'].apply(GetScore)
BaddebtScore = Final['呆账'].apply(GetScore)
CardstopedScore = Final['强制停卡记录'].apply(GetScore)
BounceScore = Final['退票'].apply(GetScore)
RefuseScore = Final['拒往记录'].apply(GetScore)
Final['历史信用风险'] = (BuguserSocre + OverdueScore * 2 + BaddebtScore * 3 + CardstopedScore * 3 + BounceScore * 3 + RefuseScore * 3)# 月刷卡额/个人月收入
CardpayPersonal = Final['月刷卡额'] / Final['个人月收入']
# 月刷卡额/家庭月收入
CardpayFamily = Final['月刷卡额'] / Final['家庭月收入']
EconomicScore = []
for i in range(Final.shape[0]):if CardpayPersonal[i] <= 1:if Final.loc[i, '借款余额'] == 1:EconomicScore.append(1)else:EconomicScore.append(0)if CardpayPersonal[i] > 1:if CardpayFamily[i] <= 1:if Final.loc[i, '借款余额'] == 1:EconomicScore.append(2)else:EconomicScore.append(1)if CardpayFamily[i] > 1:if Final.loc[i, '借款余额'] == 1:EconomicScore.append(4)else:EconomicScore.append(2)# 个人月开销/月刷卡额
OutcomeCardpay = Final['个人月开销'] / Final['月刷卡额']
OutcomeCardpayScore = []
for i in range(Final.shape[0]):if(OutcomeCardpay[i] <= 1):OutcomeCardpayScore.append(1)else:OutcomeCardpayScore.append(0)Final['经济风险情况'] = np.array(EconomicScore) + np.array(OutcomeCardpayScore)# 判断用户是否具有稳定的收入
HouseScore = []
for i in range(Final.shape[0]):if 3 <= Final.loc[i, '住家'] <= 5:HouseScore.append(0)else:HouseScore.append(1)JobScore = []
for i in range(Final.shape[0]):if(Final.loc[i, '职业'] <= 7 | Final.loc[i, '职业'] == 19 | Final.loc[i, '职业'] == 21):JobScore.append(2)if(Final.loc[i, '职业'] >= 8 & Final.loc[i, '职业'] <= 11):JobScore.append(1)if(Final.loc[i, '职业'] <= 18 & Final.loc[i, '职业'] >= 12 | Final.loc[i, '职业'] == 20 | Final.loc[i, '职业'] == 22):JobScore.append(0)AgeScore = []
for i in range(Final.shape[0]):if Final.loc[i, '年龄'] <= 2:AgeScore.append(1)else:AgeScore.append(0)Final['收入风险情况'] = np.array(HouseScore) + np.array(JobScore) + np.array(AgeScore)# 输出查看结果
Final[['历史信用风险', '经济风险情况', '收入风险情况']]

在这里插入图片描述

新属性构建后,对每个新属性的数据分布情况进行分析,其数据取值范围如下表所示。从数据中可以发现,3个新属性的取值范围差异比较大,为了消除取值差异带来的影响,需要对数据进行标准差标准化处理。

# 计算最大值和最小值
max_values = Final[['历史信用风险', '经济风险情况', '收入风险情况']].max()
min_values = Final[['历史信用风险', '经济风险情况', '收入风险情况']].min()# 创建一个新的DataFrame来存储结果
results = pd.DataFrame({'变量名称': ['最小值', '最大值'],'历史信用': [min_values['历史信用风险'], max_values['历史信用风险']],'经济风险': [min_values['经济风险情况'], max_values['经济风险情况']],'收入风险': [min_values['收入风险情况'], max_values['收入风险情况']]
})
# 设置索引,使得'变量名称'列成为行索引
results.set_index('变量名称', inplace=True)
# 打印结果
results

在这里插入图片描述

StdScaler = StandardScaler().fit(Final[['历史信用风险', '经济风险情况', '收入风险情况']])
ScoreModel = StdScaler.transform(Final[['历史信用风险', '经济风险情况', '收入风险情况']])
ScoreModel

在这里插入图片描述

四、分析与建模

构建信用卡高风险客户识别模型步骤:

  1. 对K-Means聚类算法进行参数寻优,确定合适的聚类数目。
  2. 在确定好聚类数目后根据构建的3个指标对客户进行聚类分群。
  3. 结合业务对每个客户群进行特征分析,分析其风险,并对每个客户群进行风险排名。

(一)聚类参数寻优

在K-Means聚类算法中,最关键的一个参数是k值,选择一个合适的k值有助于对数据进行更准确的分析。在评估Python聚类分群质量的指标中,当未知真实类别标签时,可以通过轮廓系数(Silhouette Coefficient)和簇内误差平方和(SSE)可以确定K-Means聚类算法中k的取值。

import numpy as np
from sklearn.cluster import KMeans
import collections
from sklearn import metrics
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'SimHei'  # 正常显示中文# 参数寻优
inertia = []
silhouettteScore = []
# 计算聚类数目为2至9时的轮廓系数值和簇内误差平方和
for i in range(2, 10):km = KMeans(n_clusters=i, random_state=12).fit(ScoreModel)y_pred = km.predict(ScoreModel)center_ = km.cluster_centers_score = metrics.silhouette_score(ScoreModel, km.labels_)silhouettteScore.append([i, score])inertia.append([i, km.inertia_])# 绘制轮廓系数图
silhouettteScore = np.array(silhouettteScore)
plt.plot(silhouettteScore[: , 0], silhouettteScore[: , 1])
plt.title('轮廓系数值 - 聚类数目')
plt.show() 
#绘制簇内误差平方和图
inertia = np.array(inertia)
plt.plot(inertia[: , 0], inertia[: , 1])
plt.title('簇内误差平方和 - 聚类数目')
plt.show() 

在这里插入图片描述
在这里插入图片描述

通过轮廓系数值图和簇内误差平方和图可以看出,聚类数目为2至3和3至4时平均畸变程度较大,簇内误差平方和的值也在聚类数目为3和4时出现了较大的拐点,再结合信用卡客户类型的实际业务情况,认为将聚类数目定k=4时比较合适。

(二)构建信用卡高风险客户识别模型

# 构建K-Means聚类模型
KMeansModel = KMeans(n_clusters=4, random_state=12).fit(ScoreModel)
Cou = collections.Counter(KMeansModel.labels_)
print(Cou)
KMeansModel.cluster_centers_   # 查看中心点
center = KMeansModel.cluster_centers_
print(center)  # 聚类中心
names = ['历史信用风险', '经济风险情况', '收入风险情况']

在这里插入图片描述

采用K-Means聚类算法进行客户分群,聚成4类,得到聚类分群的结果如下表。

聚类类别类别个数聚类中心
ZLZRZF
类别126856-0.229485660.14699398-0.83046269
类别230104.300683223.036006320.05968195
类别320419-0.229485660.066083031.08775743
类别49134-0.22948566-1.58040275-0.00959664

(三)信用卡客户风险分析

根据每种客户的类型特征,对每类客户进行归类,绘制信用卡客户分析的雷达图。

# 绘制雷达图
fig = plt.figure(figsize=(10, 8.5))
ax = fig.add_subplot(111, polar=True)  # 定义polar参数为True,设置为极坐标格式
angles = np.linspace(0, 2 * np.pi, 3, endpoint=False)
angles = np.concatenate((angles, [angles[0]]))  # 闭合
Linecolor = ['bo-', 'r+:', 'gD--', 'kv-.']  # 点线颜色
Fillcolor = ['b', 'r', 'g', 'k']
# 设置每个标签的位置
plt.xticks(angles, names)
for label, i in zip(ax.get_xticklabels(), range(0,len(names))):if i < 1:angle_text = angles[i] * (-180 / np.pi) + 90label.set_horizontalalignment('left')else:angle_text = angles[i] * (-180 / np.pi) - 90label.set_horizontalalignment('right')label.set_rotation(angle_text)
# 绘制ylabels
ax.set_rlabel_position(0)
# 设置雷达图参数
for i in range(4):data = np.concatenate((center[i], [center[i][0]]))  # 闭合ax.plot(angles, data, Linecolor[i], linewidth=2)  # 画线ax.fill(angles, data, facecolor=Fillcolor[i], alpha=0.25)  # 填充颜色ax.set_title('客户分群雷达图', va='bottom')  # 设定标题
ax.set_rlim(-2, 5)  # 设置各指标的最终范围
ax.grid(True)
plt.legend(['类别1', '类别2', '类别3', '类别4'])
plt.savefig('../img/客户分群雷达图.jpg', dpi=720) #指定分辨率保存客户分群雷达图
plt.show()

在这里插入图片描述

4个类别在雷达图中按照面积的大小排序,从高到底依次是类别2、类别3、类别1和类别4。而面积越大代表着风险综合值越高,说明越容易发生信用卡违约情况。

总结出每个客户类型的显著特征如下表。(注:加粗字体表述最大值,斜体表示最小值,正常字体为次大值。)

客户类别显著特征
类别1经济风险收入风险
类别2历史信用风险经济风险收入风险
类别3收入风险历史信用风险
类别4经济风险历史信用风险

通过上述特征分析的图表说明,每个客户类型都有显著的不同特征。基于该特征描述本案例的挖掘目标,定义客户类型为禁入类客户、高风险客户、潜在高风险客户、一般风险客户、一般客户,具体解释如下。

  • 禁入类客户。这类客户历史信用糟糕,在历史信用风险上得分最高,且经济情况不佳,目前的经济收入稳定情况也不好。他们是银行的禁入客户,不少客户曾有过呆账、强制停卡记录,给银行的信用卡工作开展带来了麻烦,甚至造成了直接损失。
  • 高风险客户。这类客户经济状况糟糕,历史行为中或多或少有瑕疵,收入稳定情况一般。因经济状况糟糕,这类客户可能无法按时按量还款,有极大的可能性给银行带来坏账或者逾期的情况。
  • 潜在高风险客户。这类客户收入稳定情况糟糕,信用风险中等,经济状况中等。这一类客户因收入稳定性糟糕,缺乏稳定的收入来源,一旦发生工作变动,房屋变动,自身的资金无法周转开来就可能发生逾期,给银行信用卡工作开展造成一定的麻烦。
  • 一般风险客户。这类客户的经济风险偏高,收入风险中等,是银行的关注对象,在某些特殊情况,例如,当资金周转困难时,有可能会导致延迟还款或逾期。
  • 一般客户。这类客户历史行为记录良好,经济情况不错,收入稳定情况上佳。他们是银行的理想客户,能按时还款,收入稳定,刷卡符合自身收入水平。

根据客户特征分析与客户类型定义,得到客户风险排名如下表。

客户类型排名排名含义
类型13一般风险客户
类型21禁入类客户及高风险客户
类型32潜在高风险客户
类型44一般客户

五、模型评价

聚类参数寻优时介绍了使用轮廓系数和簇内误差平方和进行K-Means聚类算法k参数的寻优情况,也从轮廓系数值图和簇内误差平方和图中看出,当聚类数目为4时平均畸变程度较大以及簇内误差平方和也较小。此外,当聚类数目为4时,能较为合理地对客户进行分类,说明模型的聚类效果较好。

根据对信用卡客户风险的分析,绘制不同客户类型客户数量占比饼图。

import collections
import matplotlib.pyplot as plt# 绘制不同客户类型客户数量饼图
TypeRate = collections.Counter(KMeansModel.labels_)
name_list = ['潜在高风险客户', '禁入类客户及高风险客户', '一般风险客户', '一般客户']
num_list = TypeRate.values()
print('查看各类客户数量:', num_list)
plt.figure(figsize=(8, 8))
# 绘制饼图
explode = [0, 0.1, 0, 0]  # 分离禁入类客户和高风险客户
plt.pie(num_list, labels=name_list, autopct='%1.1f%%', pctdistance=1.15, explode=explode, labeldistance=1.05, startangle=90)
plt.title('不同客户类型客户数量占比饼图')
plt.savefig('../img/不同客户类型客户数量占比饼图.jpg', dpi=720) #指定分辨率保存饼图
plt.show()

在这里插入图片描述
在这里插入图片描述

从输出结果可以看出,一般风险客户26856位,占比45.2%;潜在高风险客户20419位,占比34.4%;一般客户9134位,占比15.4%;禁入类客户及高风险客户3010位,占比5.1%。禁入类客户是银行设置的黑名单,此类客户会不断积累银行的坏账数目,给银行带来直接的经济损失。高风险客户因月刷卡额过高,极有可能存在套现行为。大量现金流出,非常不利于银行业务的健康发展。

鉴于以上分析,综合后提出以下风控建议。

  • 针对禁入类客户高风险类客户,加强对其监督,密切关注还款情况,一旦出现逾期情况需要有专人跟进还款情况,一旦出现逾期不归还情况,立刻对其进行强制停卡处理,并及时上报公安机关备案。同时将其信用记录及时上报中国人民银行征信中心,与合作银行建立起黑名单机制,拒绝为黑名单内人员办理贷款,信用卡等信用相关的业务。
  • 针对潜在高风险客户,对其提额申请慎重考虑,同时密切关注其每月刷卡额,一旦刷卡额过高,进行预警,提醒其分期减少资金压力。并定期发送其在本行的信用情况,提醒其保持良好的信用。
  • 针对一般风险客户,允许其小幅提额请求。但是需要定时提醒其还款,以及关注目前个人信用程度情况。在刷卡额超出月均刷卡额时进行提醒。
  • 针对一般客户,并不用对其设置严格管控要求,允许甚至鼓励其提额请求,定期推送信用卡相关业务介绍,以及有针对性的进行人性化服务,增加用户黏性。

小结

本案例主要目的是通过K-Means聚类算法判别出信用卡客户风险级别。重点介绍了数据探索、属性规约、属性构造。

  • 建立客户风险K-Means聚类模型,分析了每一类客户的特征。
  • 分析目前银行的信用卡客户结构。
  • 提出了风险控制相关的建议。

:以上文中的数据集及相关资源下载地址:
链接:https://pan.quark.cn/s/ace5291eefb1
提取码:w1Wc

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词