密度聚类DBSCAN详解附Python代码

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()
      

picture.image

生成一个环形数据集并在左上角添加更多数据,为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()
      

picture.image

根据可视化可知数据集被聚类为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()
      

picture.image

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()
      

picture.image

使用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()
      

picture.image

可以发现两种算法的聚类结果存在显著性差异,这与两种算法的中心思想相关,K-means是一种基于质心的聚类算法,通过最小化簇内方差将数据分为球形簇,而DBSCAN是一种基于密度的聚类算法,通过发现高密度区域实现对不规则形状和不同密度的簇的聚类,并自然地识别噪声点,其中K-means需要指定聚类簇数且为最重要参数,而DBSCAN不需要,DBSCAN最重要的参数为半径和最小样本点数目

3. 往期推荐

orange3一个不需要编程知识进行数据挖掘和机器学习的python工具箱

基于分布的四种离群值检验方法

基于K-means实现中草药红外光谱数据聚类

kNN分类详解(标准kNN、距离加权kNN)

LightGBM模型房价预测实现

Python中如何使用Joblib保存和调用模型

ARIMA模型进阶——具有季节性的SARIMAX模型实现

长短期记忆网络LSTM在时序数据预测演示

时间序列异常值检验神器——Hampel滤波器

模型选择的有利方法——网格调参

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

0
0
0
0
评论
未登录
暂无评论