物以类聚,人以群分,平常我们把人和物进行分类,今天来讲一讲如何通过DBSCAN用数据把样本进行聚类。
1. DBSCAN 定义
DBSCAN (Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的聚类算法。与K均值聚类和层次聚类不同,它将簇定义为密度相连的点的最大集合,能够把具有足够高密度的区域划分为簇,并可在噪声的空间数据库中发现任意形状的聚类。
2. DBSCAN 的原理
2.1 DBSCAN中几个常见的定义
Ε邻域: 以某个点为中心,半径为E画圆,围成的区域称为该点的E邻域
核心对象: 如果某点E邻域内的样本点数大于等于MinPts(一般为自己设定大于1的正整数),则该点为核心对象
直接密度可达: 如果p为核心对象, q在p的E邻域中,称q从对象p直接密度可达,注意p不一定从对象q直接密度可达,除非q也是核心对象。
密度可达: 对于样本集合D,给定一串样本点{p1,p2….pn},p= p1,q= pn,假如对象pi从pi-1直接密度可达,那么对象q从对象p密度可达。
密度相连: 存在样本集合D中的一点o,如果对象o到对象p和对象q都是密度可达的,那么p和q密度相联。
图1 模拟DBSCAN算法生成的三个簇
在图1中,设定MinPts=4,图中蓝色的点是核心对象(这些点E邻域中点的个数大于等于4), 黑色的点是非核心对象,灰色的点是孤立点。在同一个圈(E邻域)中的点,黑色的点从蓝色点直接密度可达。从图1中可以看出DBSCAN把所有样本分成了四类,其中三类分别在不同的簇中。每一个簇中蓝色的点(核心对象)之间是密度可达的,蓝色的点和黑色的点之间是密度相连的。还有一类为异常值(灰色的点),所以DBSCAN不仅可以做聚类分析,还可以做异常值检测。
2.2 DBSCAN 算法描述
假设要对样本集X进行DBSCAN聚类,其实就是把X中密度相连的点的最大集合作为一个簇,直到找出所有的簇即完成了聚类。下面描述具体的步骤:
(1) 检测样本集中尚未检查过的样本p,如果p未被归为某个簇或者标记位噪声(异常值),则检测其Ε邻域,若邻域内包含的样本数不少于MinPts,则建立新簇C,将邻域内的所有点加入候选集N;
(2) 对候选集N中所有尚未被处理的样本q,检测其E邻域,若邻域内包含样本数不少于MinPts的样本点,则将这些样本点加入N。如果q未归入任何一个簇,则将q加入C;
(3) 重复步骤2,继续检测N中未处理的样本,直到当前候选集N为空;
(4) 重复步骤1~3,直到所有样本都归入了某个簇或被标记为噪声。
3. DBSCAN 优缺点
3.1 优点
(1) 相比于K-Means之类的聚类算法只适用于凸样本集,DBSCAN既适用于凸样本集,也适用于非凸样本集,并且可以对任意形状的稠密数据集进行聚类(可参见下文图2)。
(2) 聚类结果不依赖初始值,结果没有偏倚。
(3) DBSCAN不仅可以做聚类分析,还可以做异常值检测,算法对数据集中的异常点不敏感。
3.2 缺点
(1) 对数据要求较高,如果样本集密度不均匀、聚类间差距较大时,DBSCAN的结果较差,最好在聚类之前对数据进行标准化处理。
(2) 距离阈值eps(E邻域的半径)和邻域内包含样本数MinPts参数较难确定,并且对结果影响较大。
(3) 如果样本集较大时,聚类收敛的时间较长。
实例:用DBSCAN对笑脸数据聚类
图2 用DBSCAN对笑脸数据进行聚类
动图素材来源(感兴趣的可以去该网址调整一下参数感受DBSCAN的聚类过程):https://www.naftaliharris.com/blog/visualizing-dbscan-clustering/
4. DBSCAN 在Python中实现代码
代码语言:javascript复制from sklearn.cluster import DBSCAN #加载库
result=DBSCAN(eps=0.5, min_samples=5, metric=’euclidean’, algorithm=’auto’, leaf_size=30, p=None).fit(X)
主要参数解析:
eps: E邻域的距离阈值,默认值0.5;
min_samples: 样本点要成为核心对象所需的E邻域样本数阈值,即前文提到的MinPts;
metric: 最近邻距离度量参数,可选欧式距离、曼哈顿距离、切比雪夫距离、马氏距离、闵可夫斯基距离、带权重闵可夫斯基距离等,默认采用欧式距离;
algorithm: 最近邻搜索算法参数,算法包括三种——蛮力实现(brute)、KD树实现(kd_tree)、球树实现(ball_tree), 如果选择auto会在上面三种算法中做权衡,选择一个拟合最优的算法;
leaf_size: 当最近邻搜索算法参数为KD树或球树时, 设定的值为停止建子树的叶子节点数量的阈值,默认值30;
p: 当最近邻距离度量参数为闵可夫斯基距离和带权重闵可夫斯基距离时,设定p=1为曼哈顿距离, p=2为欧式距离,采用默认值欧式距离时这个值为None;
5. 项目实战
背景介绍: 商户mcc在录入的时候可能由于录入人员不小心录错,或者商户故意错填mcc,以掩盖自己虚假经营的事实,导致和实际交易的mcc不符。本文用DBSCAN算法通过分析商户的交易数据,找出和实际不符的mcc,从而纠正mcc。
step1:加载数据
代码语言:javascript复制import pandas as pd
import numpy as np
mcc_dm = pd.read_csv('mcc_dm.csv')
step2:挑选变量
代码语言:javascript复制coulmns_dm = [
'all_avg_tran_amt_30d',
'all_tran_cnt_suc_pct_30d',
'card_tran_cnt_cre_pct_30d',
'all_tran_cnt_m5k_suc_pct_30d',
'tran_cnt_100int_f5_suc_pct_30d',
'ms_deb_card_cnt_pct_30d'
]
step3: 使用DBSCAN进行聚类并寻找异常样本点
代码语言:javascript复制#标准化处理
from sklearn import preprocessing
X_dm = mcc_dm[columns_dm]
X_dm_1 = preprocessint.scale(X_dm)
#DBSCAN聚类
from sklearn.cluster import DBSCAN
dm_scale_dbscan = DBSCAN(eps=2, min_samples=10).fit(X_dm_1)
X_dm['pred_scale_dbscan'] = dm_scale_dbscan.labels_
代码解析:
X_dm: 生成待入模的特征标签;
X_dm_1:标准化处理数据,减少样本集密度不均匀对算法的影响。我在分析的时候发现,如果数据不进行标准化处理,由于实际的数据很可能密度不均匀,导致DBSCAN的结果很差,最好先处理一下数据再做DBSCAN聚类;
dm_scale_dbscan =:用处理好的数据训练模型,eps的值取2,min_samples的值取10,这两个参数要根据最后结果的分析进行多次调整;
X_dm['pred_scale_dbscan']:把聚类的标签放到原始数据中 ,其中-1代表异常值;
step4: DBSCAN结果分析
代码语言:javascript复制X_dm['pred_scale_dbscan'].value_counts().sort_index() #看下落在每一组的数据分布情况
结果: -1 16
0 9832
1 160
2 52
3 23
最后通过排查发现落在-1这一组的16个商户中有15个商户的mcc存在录入错误,需要纠正mcc,验证了DBSCAN算法在实际应用中的可行性。而且落在1、2、3这些组中的商户和该mcc大部分的商户(落在0中)存在差别,可以进一步分析原因,可以先用下面的脚本从数据层面进行分析,如果想进一步确定,可以下发监控运营进行批量排查,找出差别。
代码语言:javascript复制X_dm.groupby('pred_scale_dbscan').mean()
本文是本人使用DBSCAN后的一些见解,如有不当之处恳请指正。
参考文献:
1. https://baike.so.com/doc/3105468-3273248.html
2. https://www.cnblogs.com/pinard/p/6208966.html
-end-