DBSCAN是一种密度聚类算法,用于将数据集中的样本点分成不同的簇,并能够发现噪声点,DBSCAN不需要预先指定簇的数量,而是基于数据点的密度来确定簇的形状和数量
1. DBSCAN详解
1.1 DBSCAN原理
- 核心点: 对于每个数据点,如果在其邻域内包含至少MinPts个样本点(包括该点自身),则该点被认为是核心点
- 直接密度可达: 如果一个点是核心点,那么与其在同一个簇中的所有其他点都是直接密度可达的
- 密度可达: 如果存在一个核心点序列(p1, p2, ..., pn),其中p1是核心点,pn是目标点,而pi+1是pi的直接密度可达点,那么p1与pn是密度可达的
- 密度相连: 如果存在一个核心点q,使得p和q都是密度可达的,那么p和q是密度相连的
1.2 DBSCAN数据点类别
基于以上的定义,DBSCAN将数据点分为三类:
- 核心点: 具有足够密度的点,即其周围有足够数量的样本点
- 边界点: 不是核心点,但位于核心点的邻域内
- 噪声点: 既不是核心点,也不是边界点的点
DBSCAN的主要参数包括半径ε(eps)和最小样本点数目MinPts。算法从数据集中选择一个未被访问的点,探索其邻域,如果该点是核心点,则通过密度可达性将其与其他点合并成一个簇,这个过程不断重复,直到所有点都被访问,最终,未被访问的点被标记为噪声点
1.3 DBSCAN优势
- 不需要预先指定簇的数量: DBSCAN不需要用户事先指定聚类的数量,这使得它对于不同形状和大小的簇都能有效地工作
- 对噪声点鲁棒: DBSCAN可以有效地处理噪声点,即那些不属于任何簇的点,因为它能够识别并排除它们
- 能够发现任意形状的簇: 由于DBSCAN基于密度可达性,而不是距离阈值,它可以识别出任意形状的簇,而不仅仅是球状或凸形状
- 适用于不同密度的簇: DBSCAN能够适应不同密度的簇,因为它使用局部密度来定义簇的概念
1.4 DBSCAN劣势
- 对密度不均匀的数据敏感: DBSCAN对密度不均匀的数据集可能表现不佳,因为它使用相同的密度阈值来定义所有簇,而在密度变化较大的区域可能无法有效地分割簇
- 对参数敏感: DBSCAN的性能依赖于两个主要参数,即半径 ε(eps)和最小样本点数目 MinPts。选择合适的参数可能需要一些经验,且不同的数据集可能需要不同的参数
- 可能无法处理变化密度的簇: 当簇的密度变化较大时,DBSCAN可能无法正确地将它们分割为多个簇
2. Python详解
2.1 数据生成
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_circles
from sklearn.preprocessing import StandardScaler
# 生成环形数据
X, y = make_circles(n_samples=888, noise=0.05, random_state=42, factor=0.5)
# 在左上角生成更多的数据
extra_data = np.random.normal(loc=[-1.5, 1.5], scale=0.3, size=(100, 2))
X = np.vstack([X, extra_data])
# 缩放数据
X = StandardScaler().fit_transform(X)
# 可视化数据
plt.scatter(X[:, 0], X[:, 1], c='blue', marker='o', s=30, edgecolor='k')
plt.title("DBSCAN Demonstration Data")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.show()
生成一个环形数据集并在左上角添加更多数据,为DBSCAN算法做铺垫
2.2 DBSCAN实现
from sklearn.cluster import DBSCAN
# 使用DBSCAN进行聚类
dbscan = DBSCAN(eps=0.3, min_samples=5)
y_dbscan = dbscan.fit_predict(X)
# 可视化聚类结果
plt.scatter(X[:, 0], X[:, 1], c=y_dbscan, cmap='viridis', marker='o', s=30, edgecolor='k')
plt.title("DBSCAN Clustering Result")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.show()
根据可视化可知数据集被聚类为4个簇其中一类为噪声点,这也是DBSACN的另外一个作用异常值检验,DBSCAN将那些不属于任何聚类簇的数据点视为噪声点。这些噪声点就是异常值,因为它们不符合在高密度区域中形成聚类的定义
2.3 删除噪声点可视化
# 获取非噪声点的索引
non_noise_indices = np.where(y_dbscan != -1)[0]
# 可视化聚类结果并加上图例
for label in np.unique(y_dbscan[non_noise_indices]):
plt.scatter(X[y_dbscan == label, 0], X[y_dbscan == label, 1], label=f'Cluster {label}', marker='o', s=30, edgecolor='k')
plt.legend()
plt.title("DBSCAN Clustering Result with Legend")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.show()
2.4 K-means聚类
from sklearn.cluster import KMeans
# 使用K-means进行聚类,假设聚类数为3
kmeans = KMeans(n_clusters=3, random_state=42)
y_kmeans = kmeans.fit_predict(X)
# 可视化K-means聚类结果
plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, cmap='viridis', marker='o', s=30, edgecolor='k')
plt.title("K-means Clustering Result")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.show()
使用K-means聚类算法对同一个数据集进行聚类,聚为3个簇
2.5 K-means和DBSCAN聚类对比
# 创建画布,左右两侧显示
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# 左侧:K-means聚类结果
for label in np.unique(y_kmeans):
axes[0].scatter(X[y_kmeans == label, 0], X[y_kmeans == label, 1], label=f'Cluster {label}', marker='o', s=30, edgecolor='k')
axes[0].legend()
axes[0].set_title("K-means Clustering Result with Legend")
axes[0].set_xlabel("Feature 1")
axes[0].set_ylabel("Feature 2")
# 右侧:DBSCAN聚类结果
non_noise_indices = np.where(y_dbscan != -1)[0]
for label in np.unique(y_dbscan[non_noise_indices]):
axes[1].scatter(X[y_dbscan == label, 0], X[y_dbscan == label, 1], label=f'Cluster {label}', marker='o', s=30, edgecolor='k')
axes[1].legend()
axes[1].set_title("DBSCAN Clustering Result with Legend")
axes[1].set_xlabel("Feature 1")
axes[1].set_ylabel("Feature 2")
plt.show()
可以发现两种算法的聚类结果存在显著性差异,这与两种算法的中心思想相关,K-means是一种基于质心的聚类算法,通过最小化簇内方差将数据分为球形簇,而DBSCAN是一种基于密度的聚类算法,通过发现高密度区域实现对不规则形状和不同密度的簇的聚类,并自然地识别噪声点,其中K-means需要指定聚类簇数且为最重要参数,而DBSCAN不需要,DBSCAN最重要的参数为半径和最小样本点数目
3. 往期推荐
orange3一个不需要编程知识进行数据挖掘和机器学习的python工具箱
如果你对类似于这样的文章感兴趣。
欢迎关注、点赞、转发~
