DBSCAN算法简述:
为什么出现DBSCAN算法?
当大家一说起聚类算法时候,最先想到的估计就是K-Means或Mean-Shift算法了。但是,K-Means和Mean-Shift算法是通过距离聚类的方式来进行判别,需要设定类别参数,同时聚类的结果都是球状的簇。如果是非球状的分布结构,那么K-Means算法效果并不好。非球状结构的分布如下:
像上述这样的分布结构,如果使用K-Means算法的话,聚类效果将会很差。那么这个时候DBSCAN算法就横空出世来解决这些问题。
简单点说基于密度的聚类算法(Density-Based Spatial Clustering of Applications with Noise,DBSCAN)是一种基于密度的空间策略来进行聚类。通过初始化邻域半径 ϵ ϵ ϵ与最小点集个数 M i n p t s Minpts Minpts设定,来进行条件判断(核心点、边界点、噪音点等)迭代进行聚类。
DBSCAN算法原理:
1 首先初始化DBSCAN算法的两个参数:邻域半径与最小点集个数的参数设定;
2 选择一个初始点,判断是否是核心点,对于每一个核心点:选择一个未处理过的核心点,通过密度可达的原理对样本进行聚类生成簇。
3 迭代重复以上的步骤直达所有的核心点都处理结束。
推荐一个DBSCAN算法动态显示聚类过程网站:传送门。
解释关于DBSCAN算法相关名词定义:
ϵ ϵ ϵ邻域与 M i n p t s Minpts Minpts:
我们使用DBSCAN算法时候,需要初始化两个参数: ϵ ϵ ϵ代表判断该点是不是核心点的密度半径, M i n − p t s Min-pts Min−pts为在判断该点为中心,半径为 ϵ ϵ ϵ的点集个数判断指标。
核心点:
如上图所示,将设半径设为 ϵ = 2 ϵ=2 ϵ=2同时 M i n p t s = 3 Minpts=3 Minpts=3时候,那么以上图红色的小方块为例:以它为圆心,半径为3的圆区域发现它的点数( > M i n p t s >Minpts >Minpts)大于3,即红色小方块为核心点。
边界点:
我们发现红色如果以红色小方块邻域的三个蓝色圆心,继续以它们为中心,半径为3的区域内并没有超过三个点,但是它们在红色小方块为核心点的区域内,那么它们属于边界点。
噪音点:
噪音点就是既不是核心点也不是边界点的第三种情况。
下面在解释密度直达、密度可达、密度相连的相关定义,首先看下示意图2如下:
上图2分别展示密度直达、密度可达、密度相连的相关定义,图(a)分别说明 p p p为边缘点, q q q为核心点, r r r为噪音点。
密度直达:
定义:样本点 p p p是由样本点 q q q对于参数 { ϵ , M i n p t s } \{ϵ,Minpts\} {ϵ,Minpts}密度直达,满足条件为 q q q是核心点同时 p p p点在以 q q q为核心点的圆区域内。显示示意图(b)
密度可达:
定义:如果存在一系列样本点 p 1 , p 2 , . . . , p n p_1,p_2,...,p_n p1,p2,...,pn(其中 p 1 = q p_1=q p1=q, p n = p p_n=p pn=p)使得 p i + 1 p_{i+1} pi+1可由样本点 p i p_i pi密度直达,那么样本点 p p p可由样本点 q q q密度可达。示意图(c)
密度相连:
定义:如果样本点 o o o对于样本点 p p p是密度可达的,同时样本点 o o o对于样本点 q q q也是密度可达的,那么我们称作样本点 p p p与样本点 q q q是密度相连的。示意图(d)
概念解释小结:
密度直达:核心点 q q q邻域内存在边缘点 p p p,那么我们称作样本点 p p p是由样本点 q q q密度直达的。( p p p与 q q q是相邻的);
密度可达:样本点 p p p是由一系列核心点传递到核心点 q q q的,那么我们称作样本点 p p p是由样本点 q q q密度可达。( p p p与 q q q具有传递性);
密度相连:就是存在样本点 o o o对样本点 p p p密度可达,同时又对样本点 q q q密度可达,那么样本点 p p p与样本点 q q q密度相连。(某一个中间点到 p p p、 q q q密度可达单方向传递性);
DBSCAN算法优缺点:
优点:
较其它聚类策略,例如K-Means只能适用于凸数据集,DBSCAN算法可以对任意形状的稠密数据集有效的聚类。
DBSCAN聚类对异常点抗干扰性强,即对受孤立的点影响很小,即对数据集中的异常点不明感。
缺点:
如果样本集的密度不均匀,聚类间距相差很大时,聚类质量较差,所以不适合使用DBSCAN算法。
针对大数据样本集,聚类收敛时间较长(目前改进是通过KD树快速搜索或者对球树规模限制).
DBSCAN有两个参数是经验设置(调参不是很容易):距离阈值 ϵ ϵ ϵ,邻域样本数阈值 M i n p t s Minpts Minpts,这两个参数设置都会对聚类效果影响很大。参数建议根据数据量和具体应用场景进行调节与设定。
DBSCAN算法Python代码实践:
# -*- coding:utf-8 -*-
import numpy as np
from sklearn.cluster import DBSCAN
from sklearn import metrics
from sklearn.datasets.samples_generator import make_blobs
from sklearn.preprocessing import StandardScaler
# Generate sample data
centers = [[1, 1], [-1, -1], [1, -1]]
X, labels_true = make_blobs(n_samples=750, centers=centers,
cluster_std=0.4, random_state=0)
X = StandardScaler().fit_transform(X)
# Compute DBSCAN Algorithm
db = DBSCAN(eps=0.3, min_samples=10).fit(X)
core_samples_mask = np.zeros_like(db.labels_, dtype=bool)
core_samples_mask[db.core_sample_indices_] = True
labels = db.labels_
# Number of clusters in labels, ignoring noise if present
n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)
n_noise_ = list(labels).count(-1)
print('Estimanted number of cluster: %d' % n_clusters_)
print('Estimated number of noise points: %d' % n_noise_)
print('Homogeneity: %0.3f' % metrics.homogeneity_score(labels_true, labels))
print('Completeness: %0.3f' % metrics.completeness_score(labels_true, labels))
print('V-measure: 0.3f' % metrics.v_measure_score(labels_true, labels))
print('Adjusted Rand Index: 0.3f'
% metrics.adjusted_rand_score(labels_true, labels))
print('Adjusted Mutual Information: %0.3f'
% metrics.adjusted_mutual_info_score(labels_true, labels))
print('Silhouette Coefficient: %0.3f' % metrics.silhouette_score(X, labels))
# plot result
import matplotlib.pyplot as plt
# Black removed and is used for noise instead
unique_labels = set(labels)
colors = [plt.cm.Spectral(each)
for each in np.linspace(0, 1, len(unique_labels))]
for k, col in zip(unique_labels, colors):
if k == -1:
# Black used for noise
col = [0, 0, 0, 1]
class_member_mask = (labels == k)
xy = X[class_member_mask & core_samples_mask]
plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),
markeredgecolor='k', markersize=14)
xy = X[class_member_mask & ~core_samples_mask]
plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),
markeredgecolor='k', markersize=6)
plt.title('Estimated number of clusters: %d' % n_clusters_)
plt.show()