信贷风控实战(七)——群组划分or聚类
信贷风控领域还有一个比较重要的环节,就是群组划分。一方面可以对客群进行一定的粗筛,另一方面也可以用来对已有的欺诈样本进行欺诈类别发现,以识别出不同的欺诈行为表现。在信贷风控实践中,我们可以使用聚类算法进行简单的群组划分,另外如果基于知识图谱或者复杂关系网络,我们还可以使用社区发现算法基于图进行一些群组的划分。常用的聚类算法有很多种,可以分别适用于不同数据分布情况下的聚类,这里主要介绍两种比较常用的聚类算法:k-Means和DBSCAN。

k-Means
k-Means是一个比较经典的无监督聚类算法,该算法以最小化平方误差和为目标,在选定k的基础上,将样本点分发到指定的聚类中心上。下面简单的介绍一下k-Means算法的基本过程:
- 指定需要划分成的聚类个数k, 和最大迭代次数。
- 在样本空间中,随机选择k个样本点作为初始的聚类中心,然后计算样本空间中每个样本点与每个聚类中心的距离(在不同的场景下可以选择不同的距离度量方式,如欧氏距离,曼哈顿距离等)。将每个样本点划分到离它最近的聚类中心上,完成一次迭代。
- 求出每个聚类的质心,并将该质心作为新的聚类中心,然后迭代执行步骤2。当达到指定的迭代次数,或者质心的变化所引起的SSE的变化小于指定阈值时,即可停止迭代。
- 返回聚类结果。
通过以上计算过程,我们可以发现k-Means聚类算法存在如下几个问题:
- 聚类中心的个数k怎么选取,选取多少合适?
- 随机初始化k个质心会导致算法结果的不稳定。
- k-Means算法在聚类的时候以质心为聚类参考,仅对“球形”分布的样本有效,对于一些分布比较奇特的样本,聚类效果较差。
k-Means聚类算法中k的选择,一般有elbow方法和purity方法。下面我们以elbow方法为例展示k的选择过程。
导入数据
# 引入依赖包
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.cluster import KMeans
# 数据导入
data = pd.read_csv('Acard.txt')
data.head()
obs_mth bad_ind uid td_score jxl_score mj_score rh_score zzc_score zcx_score person_info finance_info credit_info act_info
0 2018-10-31 0.0 A10000005 0.675349 0.144072 0.186899 0.483640 0.928328 0.369644 -0.322581 0.023810 0.00 0.217949
1 2018-07-31 0.0 A1000002 0.825269 0.398688 0.139396 0.843725 0.605194 0.406122 -0.128677 0.023810 0.00 0.423077
2 2018-09-30 0.0 A1000011 0.315406 0.629745 0.535854 0.197392 0.614416 0.320731 0.062660 0.023810 0.10 0.448718
3 2018-07-31 0.0 A10000481 0.002386 0.609360 0.366081 0.342243 0.870006 0.288692 0.078853 0.071429 0.05 0.179487
4 2018-07-31 0.0 A1000069 0.406310 0.405352 0.783015 0.563953 0.715454 0.512554 -0.261014 0.023810 0.00 0.423077
查看数据状况
data.describe()
bad_ind td_score jxl_score mj_score rh_score zzc_score zcx_score person_info finance_info credit_info act_info
count 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000 95806.000000
mean 0.018767 0.499739 0.499338 0.501640 0.498407 0.500627 0.499672 -0.078229 0.036763 0.063626 0.236197
std 0.135702 0.288349 0.288850 0.288679 0.287797 0.289067 0.289137 0.156859 0.039687 0.143098 0.157132
min 0.000000 0.000005 0.000013 0.000007 0.000005 0.000012 0.000010 -0.322581 0.023810 0.000000 0.076923
25% 0.000000 0.250104 0.249045 0.250517 0.250115 0.249501 0.248318 -0.261014 0.023810 0.000000 0.076923
50% 0.000000 0.500719 0.499795 0.503048 0.497466 0.501688 0.499130 -0.053718 0.023810 0.000000 0.205128
75% 0.000000 0.747984 0.748646 0.752032 0.747188 0.750986 0.750683 0.078853 0.023810 0.060000 0.346154
max 1.000000 0.999999 0.999985 0.999993 0.999986 0.999998 0.999987 0.078853 1.023810 1.000000 1.089744
通过describe观察,我们发现这些数据都是经过特殊处理的数据,不同特征之间不存在明显的量纲问题,因此无需进行归一化。这里需要注意的是,如果各特征之间存在明显的量纲差异,一定要归一化,一定要归一化!!!
Elbow方法选k
# 选择特征列
features = data[['td_score', 'jxl_score', 'mj_score',
'rh_score', 'zzc_score', 'zcx_score', 'person_info', 'finance_info',
'credit_info', 'act_info']]
# 使用手肘法选取最优K值
sse = {}
for k in range(1, 10):
kmeans = KMeans(n_clusters=k).fit(features)
features["clusters"] = kmeans.labels_
sse[k] = kmeans.inertia_
plt.figure()
plt.plot(list(sse.keys()), list(sse.values()))
plt.xlabel("Number of cluster")
plt.ylabel("SSE")
plt.show()

通过观察我们发现,在k为2和4的时候,SSE的变化最大,这里我们选择k为4进行k-Means聚类。
##此处选择四个簇
model=KMeans(n_clusters=4)
model.fit(features)
predicted_label = model.predict(features)
features['clusters'] = predicted_label
features
聚类结果如下:

由于随机初始化k个质心会导致算法结果的不稳定。其实上面的算法,多执行几次的话就会发现我们得到的SSE的图是不一样的,因此在初始化k个聚类中心的时候也有一些方式,比如:选取距离尽量远的K个样本点作为中心点:随机选取第一个样本C1作为第一个中心点,遍历所有样本选取离C1最远的样本C2为第二个中心点,以此类推,选出K个初始中心点。针对k-Means存在的第三个问题,通常需要使用其他的算法来解决,比如我们接下来要介绍的DBSCAN。
DBSCAN
DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一个比较有代表性的基于密度的聚类算法。与k-Means聚类方法不同,它将簇定义为密度相连的点的最大集合,能够把具有足够高密度的区域划分为簇,并可在噪声的空间数据中发现任意形状的聚类。因此DBSCAN除了能实现聚类外,还能顺带把异常检测的事儿给做了,所有不能划分到某个簇中的数据都可以认为是异常数据。在简单介绍DBSCAN算法的实现过程之前,先介绍几个跟DBSCAN相关的概念:
领域:指的是样本点为中心,半径为半径
划定的范围区域。领域半径
是我们在调用这个算法的时候需要输入的入参之一,
用来指示当前样本的领域大小。
最小点数MinPts:最小点数用来评估某个样本点领域
\epsilon
中的样本点数小于MinPts,则证明其密度比较系数。最小点数MinPts也是算法的输入参数之一。
核心点:如果一个样本点的领域内的样本点数不小于最小点数MinPts,则称之为核心点。
边界点:不属于核心点但在某个核心点的领域内的点叫做边界点。
噪声点:既不属于核心点也不属于边界点的点称之为是噪声点。
密度直达:如果P为核心点,Q在P的邻域内,那么称P到Q密度直达。任何核心点到其自身密度直达,密度直达不具有对称性,如果P到Q密度直达,那么Q到P不一定密度直达,因为Q不不一定为核心点。
密度可达:如果存在核心点P1,P2,P2,P3,…,Pn,且P1到P2密度直达,P2到P3密度直达,……,P(n-1)到Pn密度直达,Pn到Q密度直达,则P1到Q密度可达。密度可达也不具有对称性,因为密度直达不具有对称性。
密度相连:如果存在核心点S,使得S到P和Q都密度可达,则P和Q密度相连。密度相连具有对称性,如果P和Q密度相连,那么Q和P也一定密度相连。密度相连的两个点属于同一个聚类簇。
非密度相连:如果两个点不属于密度相连关系,则两个点非密度相连。非密度相连的两个点属于不同的聚类簇,或者其中存在噪声点。
在介绍完上述概念之后,我们正式介绍DBSCAN算法的流程:
- 从数据集中任意选取一个数据对象点p
- 如果对于
领域和最小点数MinPts,所选取的数据对象点p为核心点,则从样本空间中找出所有从p密度可达的数据对象点,形成一个簇;
- 如果选取的数据对象点p是边界点,进入下一轮,重新选择另一个数据样本点;
- 重复步骤2和3,直到所有样本点都被处理。
代码实现如下:
导入数据
# 引入依赖包
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.cluster import DBSCAN
# 数据导入
data = pd.read_csv('Acard.txt')
data.head()
obs_mth bad_ind uid td_score jxl_score mj_score rh_score zzc_score zcx_score person_info finance_info credit_info act_info
0 2018-10-31 0.0 A10000005 0.675349 0.144072 0.186899 0.483640 0.928328 0.369644 -0.322581 0.023810 0.00 0.217949
1 2018-07-31 0.0 A1000002 0.825269 0.398688 0.139396 0.843725 0.605194 0.406122 -0.128677 0.023810 0.00 0.423077
2 2018-09-30 0.0 A1000011 0.315406 0.629745 0.535854 0.197392 0.614416 0.320731 0.062660 0.023810 0.10 0.448718
3 2018-07-31 0.0 A10000481 0.002386 0.609360 0.366081 0.342243 0.870006 0.288692 0.078853 0.071429 0.05 0.179487
4 2018-07-31 0.0 A1000069 0.406310 0.405352 0.783015 0.563953 0.715454 0.512554 -0.261014 0.023810 0.00 0.423077
DBSCAN聚类
# 选择特征列
features = data[['td_score', 'jxl_score', 'mj_score',
'rh_score', 'zzc_score', 'zcx_score', 'person_info', 'finance_info',
'credit_info', 'act_info']]
# 指定入参
clustering = DBSCAN(eps=0.5, min_samples=5).fit(features)
features['clusters'] = clustering.labels_
features.head()
td_score jxl_score mj_score rh_score zzc_score zcx_score person_info finance_info credit_info act_info clusters
0 0.675349 0.144072 0.186899 0.483640 0.928328 0.369644 -0.322581 0.023810 0.00 0.217949 0
1 0.825269 0.398688 0.139396 0.843725 0.605194 0.406122 -0.128677 0.023810 0.00 0.423077 0
2 0.315406 0.629745 0.535854 0.197392 0.614416 0.320731 0.062660 0.023810 0.10 0.448718 0
3 0.002386 0.609360 0.366081 0.342243 0.870006 0.288692 0.078853 0.071429 0.05 0.179487 0
4 0.406310 0.405352 0.783015 0.563953 0.715454 0.512554 -0.261014 0.023810 0.00 0.423077 0
与k-Means不同,DBSCAN作为一种基于密度的聚类算法,其最终生成的簇的数量并不是在算法执行的时候认为设定的,而是根据输入的邻域半径和邻域中最小样本数决定的。因此使用DBSCAN前需要充分了解当前数据,这样才能设定合理的密度条件,以达到正确的聚类目标。相比较K-Means中K值得设定,DBSCAN得参数调整相对较复杂,需要对领域半径和最小样本数MinPts 同时进行联合调参。
DBSCAN,因此关于DBSCAN有如下问题需要注意:
- 样本集的密度不均匀、聚类间距差相差很大时,DBSCAN得聚类质量较差。
- 样本集较大时,算法收敛时间较长,此时可以对搜索最近邻时建立的 KD 树来加速选最近点的性能。
- 需要对距离阈值
和邻域样本数阈值MinPts进行联合调参,不同的参数组合对聚类效果有较大影响。
总结一下
- 与k-Means方法相比,DBSCAN不需要事先知道要形成的簇类的数量。
- 与k-Means方法相比,DBSCAN可以发现任意形状的簇类。
- DBSCAN能够识别出样本点中的噪声点。
- 如果数据集中存在不同密度的簇或者嵌套簇,则DBSCAN 算法无法处理。
信贷风控实战系列
信贷风控实战(一)——建模流程总览
信贷风控实战(二)——策略生成及规则挖掘
信贷风控实战(三)——评分卡建模之逻辑回归
信贷风控实战(四)——评分卡建模之XGBoost
信贷风控实战(五)——特征工程
信贷风控实战(六)——异常检测
信贷风控实战(七)——群组划分or聚类