DBSCAN
是一种典型的基于密度的聚类算法,基于一组邻域 ( ϵ , M i n P t s ) (\epsilon, MinPts) (ϵ,MinPts)来描述样本集的紧密程度。其中 ϵ \epsilon ϵ描述了某一样本的邻域距离阈值, M i n P t s MinPts MinPts描述了某一样本的距离为 ϵ \epsilon ϵ的邻域中样本个数的阈值。
在DBSCAN
算法中将数据点分为以下三类:
在DBSCAN
算法中还定义了如下概念:
上图 M i n P t s = 5 MinPts=5 MinPts=5,红色的样本都是核心点,因为其 ϵ \epsilon ϵ邻域至少有5个样本。黑色的样本是非核心点,其中红色样本邻域内的黑色样本为边界点,其他黑色样本为噪音点。所有核心点密度直达的样本在以红色样本为中心的超球体内,如果不在超球体内,则不能密度直达。图中用绿色箭头连起来的核心点组成了密度可达的样本序列。在这些密度可达的样本序列的 ϵ \epsilon ϵ邻域内所有的样本相互都是密度相连的。
输 入 : 样 本 集 D = { x 1 , x 2 , . . . , x n } , 邻 域 参 数 ( ϵ , M i n P t s ) , 样 本 距 离 度 量 方 式 输入:样本集D=\{x_1,x_2,...,x_n\},邻域参数(\epsilon,MinPts),样本距离度量方式 输入:样本集D={ x1,x2,...,xn},邻域参数(ϵ,MinPts),样本距离度量方式
输 出 : 簇 划 分 C = { C 1 , C 2 , . . . , C k } 输出:簇划分C=\{C_1,C_2,...,C_k\} 输出:簇划分C={ C1,C2,...,Ck}
初始化核心点集合 Ω = ∅ \Omega=\varnothing Ω=∅,初始化聚类簇数 k = 0 k=0 k=0,初始化为访问集合 Γ = D \Gamma=D Γ=D,簇划分 C = ∅ C=\varnothing C=∅
对于 i = 1 , 2 , . . . , n i=1,2,...,n i=1,2,...,n,按下面步骤找出所有的核心点:
如果核心点集合 Ω = ∅ \Omega=\varnothing Ω=∅,结束,否则转入步骤4
在核心点集合 Ω \Omega Ω中,随机选择一个核心点 o o o,初始化当前簇核心点队列 Ω c u r = { o } \Omega_{cur}=\{o\} Ωcur={ o},初始化类别序号 k = k + 1 k=k+1 k=k+1,初始化当前簇样本集合 C k = { o } C_k=\{o\} Ck={ o},更新为访问样本集合 Γ = Γ − { o } \Gamma=\Gamma-\{o\} Γ=Γ−{ o}
如果当前核心点队列 Ω c u r = ∅ \Omega_{cur}=\varnothing Ωcur=∅,则当前簇 C k C_k Ck生成完毕,更新簇划分 C = { C 1 , C 2 , . . . , C k } C=\{C_1,C_2,...,C_k\} C={ C1,C2,...,Ck},更新核心点集合 Ω = Ω − C k \Omega=\Omega-C_k Ω=Ω−Ck,转入步骤3。否则更新核心点集合 Ω = Ω − C k \Omega=\Omega-C_k Ω=Ω−Ck
在当前簇核心点队列 Ω c u r \Omega_{cur} Ωcur中取出一个核心点 o ′ o' o′,通过邻域阈值 ϵ \epsilon ϵ找出所有的 ϵ \epsilon ϵ邻域子样本集 N ϵ ( o ′ ) N_\epsilon(o') Nϵ(o′),令 Δ = N ϵ ( o ′ ) ∩ Γ \Delta=N_\epsilon(o') \cap \Gamma Δ=Nϵ(o′)∩Γ,更新当前簇样本集合 C k = C k ∪ Δ C_k=C_k \cup \Delta Ck=Ck∪Δ,更新为访问样本集合 Γ = Γ − Δ \Gamma = \Gamma - \Delta Γ=Γ−Δ,更新 Ω c u r = Ω c u r ∪ ( Δ ∩ Ω ) − { o ′ } \Omega_{cur}=\Omega_{cur} \cup (\Delta \cap \Omega)-\{o'\} Ωcur=Ωcur∪(Δ∩Ω)−{ o′},转入步骤5
简单来说:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import cluster, datasets
from sklearn.preprocessing import StandardScaler
np.random.seed(0)
# 构建数据
n_samples = 1500
noisy_circles = datasets.make_circles(n_samples=n_samples, factor=0.5, noise=0.05)
noisy_moons = datasets.make_moons(n_samples=n_samples, noise=0.05)
blobs = datasets.make_blobs(n_samples=n_samples, random_state=8)
data_sets = [
(
noisy_circles,
{
"eps": 0.3,
"min_samples": 5
}
),
(
noisy_moons,
{
"eps": 0.3,
"min_samples": 5
}
),
(
blobs,
{
"eps": 0.3,
"min_samples": 5
}
)
]
colors = ["#377eb8", "#ff7f00", "#4daf4a"]
plt.figure(figsize=(15, 5))
for i_dataset, (dataset, algo_params) in enumerate(data_sets):
# 模型参数
params = algo_params
# 数据
X, y = dataset
X = StandardScaler().fit_transform(X)
# 创建DBSCAN
dbscan = cluster.DBSCAN(eps=params["eps"], min_samples=params['min_samples'])
# 训练
dbscan.fit(X)
# 预测
y_pred = dbscan.labels_.astype(int)
y_pred_colors = []
for i in y_pred:
y_pred_colors.append(colors[i])
plt.subplot(1, 3, i_dataset+1)
plt.scatter(X[:, 0], X[:, 1], color=y_pred_colors)
plt.show()
优点:
K-Means
、Mean Shift
之类的聚类算法一般只适用于凸数据集K-Means
之类的聚类算法初始值对聚类结果有很大影响。缺点:
DBSCAN
聚类一般不适合。KD
树或者球树进行规模限制来改进。K-Means
之类的聚类算法稍复杂,主要需要对距离阈值 ϵ \epsilon ϵ,邻域样本数阈值 M i n P t s MinPts MinPts联合调参,不同的参数组合对最后的聚类效果有较大影响。