DBSCAN,Density-Based Spatial Clustering of Applications with Noise,具有噪声的基于密度的聚类算法
VS KMeans
Kmeans 是最常用的聚类算法之一,但它只适用于 凸样本集,而 DBSCAN 适用于 凸样本集和非凸样本集,更多的用于 非凸样本集;
记住这一点即可:Kmeans 只能生成球形簇,DBSCAN 可以生成任意形状的簇
算法原理
DBSCAN 是一种基于密度的聚类算法,其核心是根据样本分布的紧密程度来划分类别
形象描述
DBSCAN 的原理类似传销,传销组织会分成一个个窝点(类别),就是一拨人租个房;
起初窝点里只有一个人(随机找一个点);
然后这个人(核心对象)有很多亲戚朋友(关系近),他就通过骗取亲戚朋友发展下线(直接下线叫密度直达),骗来的人也住进了窝点;
然后每个下线(新的核心对象)也有很多亲戚朋友,也通过同样的方式发展自己的下线,然后下线的下线也住进了窝点;
上上线 和 新来的下线(间接下线) 通过 上线 住进了一个窝点(密度可达),也就成了一类;
然后循环往复,直到某个人周围没有亲戚朋友(边界点),完了,生意做不下去了;
但最终这个窝点的人都认识了(密度相连);
另起一个窝点吧(新的类别),
重复上面的过程,最终形成一个个窝点;
可能有些窝点很特别,当这个窝点只有一个人时,这个人周围就已经没有亲戚朋友了,这个窝点就没用了(孤立点,异常值)
数学描述
DBSCAN 通过不断寻找核心对象来确定样本类别,其中有两个重要参数 (ε,MinPts);
假设我的样本集是D=(x1,x2,...,xm), 则DBSCAN具体的描述定义如下:
1)ϵ-邻域:对于xj€D,其ϵ-邻域包含样本集D中与xj的距离不大于ϵ的子样本集,【在 xj 周围画个 以 ε 为半径的圆】
2 ) 核心对象:对于任一样本xj€D,如果其ϵ-邻域内至少包含MinPts个样本,则称其是核心对象。 【在 xj 周围画个半径为 ε 的圆,圆内的样本数大于等于 MinPts 】
3)密度直达:如果xi位于xj的ϵ-邻域中,且xj是核心对象,则称xi由xj密度直达。【圆心 和 圆内的点 叫密度直达】
注意反之不一定成立,即此时不能说xj由xi密度直达, 除非且xi也是核心对象。
4)密度可达:对于xi和xj,如果存在样本序列p1,p2,...,pT,满足p1=xi,pT=xj, 且pt+1由pt密度直达,则称x由xi密度可达。
也就是说,密度可达满足传递性。此时序列中的传递样本p1,p2,...,pT−1均为核心对象,因为只有核心对象才能使其他样本密度直达。
注意密度可达也不满足对称性,这个可以由密度直达的不对称性得出。
5)密度相连:对于xi和xj,如果存在核心对象样本xk,使xi和xj均由xk密度可达,则称xi和xj密度相连。注意密度相连关系是满足对称性的。
从下图可以很容易理解上述定义,图中MinPts=5,红色的点都是核心对象,因为其ϵ-邻域至少有5个样本。黑色的样本是非核心对象。
所有核心对象密度直达的样本在以红色核心对象为中心的超球体内,如果不在超球体内,则不能密度直达。
图中用绿色箭头连起来的核心对象组成了密度可达的样本序列。在这些密度可达的样本序列的ϵ-邻域内所有的样本相互都是密度相连的。
DBSCAN 还有3个点描述:
- 核心点:即核心对象,core point
- 边界点:与某个核心对象密度直达,但其邻域内少于 MinPts 个点,但他仍被归于和核心对象一个簇,border point
- 离群点:也叫异常值,不和任意核心对象密度直达,自己也不是核心对象,outlier point
算法步骤
找了个图,思路还是比较清晰的
注意, 某些样本可能到两个核心对象的距离都小于ϵ,但是这两个核心对象不是密度直达,不属于同一个聚类簇,那么如何界定这个样本的类别呢?
一般来说,DBSCAN采用先来后到,先进行聚类的类别簇会标记这个样本为它的类别。也就是说DBSCAN的算法不是完全稳定的算法
优点
1. 无需指定 类别数 K
2. 对异常值不敏感
3. 可以形成任意形状的簇
缺点
1. 对于分布紧密程度比较均匀的样本集不太适用
2. 对于样本集很大,维度很高的样本集,计算量太大,效率较低 【此时可以对搜索最近邻时建立的KD树或者球树进行规模限制来改进。】
3. 受 (ε,MinPts) 参数影响较大
Sklearn 用法
核心参数
def __init__(self, eps=0.5, min_samples=5, metric='euclidean', metric_params=None, algorithm='auto', leaf_size=30, p=None, n_jobs=1):
metric 可指定计算距离的方式
返回值
core_sample_indices_ : 核心点的索引,因为labels_不能区分核心点还是边界点,所以需要用这个索引确定核心点
components_:训练样本的核心点
labels_:每个点所属集群的标签,-1代表噪声点
示例代码
import numpy as np from sklearn.cluster import DBSCAN X = np.array([[1, 2], [2, 2], [2, 3], [-25, -80], [8, 7], [8, 8], [25, 80], [6, 8]]) clustering = DBSCAN(eps=3, min_samples=2).fit(X) print(clustering.labels_) # [ 0 0 0 -1 1 1 -1 1] 异常点被标记为-1 index = clustering.core_sample_indices_ # 核心对象的下标 print(index) # [0 1 2 4 5 7] core_sample = X[index] # 核心对象 print(core_sample) # [[1 2] # [2 2] # [2 3] # [8 7] # [8 8] # [6 8]] print(clustering.components_) # 核心对象,同上 # [[1 2] # [2 2] # [2 3] # [8 7] # [8 8] # [6 8]]
参考资料:
https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html 官网
https://www.cnblogs.com/pinard/p/6208966.html DBSCAN密度聚类算法
https://www.cnblogs.com/pinard/p/6217852.html 用scikit-learn学习DBSCAN聚类
https://zhuanlan.zhihu.com/p/185623849 详解DBSCAN聚类
https://www.jianshu.com/p/e594c2ce0ac0 DBSCAN 算法