三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

机器学习入门:DBSCAN 聚类

机器学习入门:DBSCAN 聚类

机器学习入门:DBSCAN 聚类

前言:本文是“机器学习入门”系列的第九站。上一站我们学习了 K-Means 聚类,它通过 K 个质心将数据划分成球形簇,但需要预先指定 K 值,且只能发现凸形簇。本篇我们将学习另一种完全不同的聚类算法——DBSCAN。它不需要指定簇的数量,能发现任意形状的簇,还能自动识别噪声点。其核心思想是:将密度足够高的区域划分为簇,低密度区域的点则标记为噪声

目录

  • 一、认识 DBSCAN 聚类
  • 二、DBSCAN 的核心原理
  • 三、DBSCAN vs K-Means
  • 四、DBSCAN 的优缺点
  • 五、典型应用场景
  • 六、核心 API 速查
  • 七、实战案例:啤酒聚类分析
  • 八、总结

一、认识 DBSCAN 聚类

1.1 什么是 DBSCAN?

DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的无监督聚类算法。它的核心特点是能根据数据的密度分布自动发现任意形状的簇,同时还能识别出数据中的噪声点。

通俗理解:想象你在地图上标注了一堆地点。DBSCAN 要做的事情是:找到那些“邻居特别多”的核心区域,从这些区域向外扩散,把所有能连通的密集区域圈成一个簇。而那些孤零零的、周围没什么邻居的点,就被标记为“噪声”。

DBSCAN 用于聚类。它不依赖标签,仅凭数据本身的密度分布进行分组。

1.2 为什么要用 DBSCAN?

K-Means 有两个明显的局限:

  1. 必须预先指定 K 值:在无监督学习中,我们往往不知道数据应该分成几类。
  2. 只能发现凸形簇:对于环形、S 形等非凸形状的数据,K-Means 效果很差。

DBSCAN 正是为了解决这两个问题而生的。

二、DBSCAN 的核心原理

2.1 两个核心参数

DBSCAN 通过两个参数来定义“密度”:

参数含义说明
ε(eps)邻域半径判断“邻居”的距离阈值。两个样本距离小于 ε 时,认为是邻居
min_samples(MinPts)最小样本数判断“核心点”的密度阈值。某点 ε 邻域内至少有 min_samples 个样本时,该点才被视为核心点

2.2 三类样本点

基于这两个参数,DBSCAN 将样本点分为三类:

类型定义
核心点(Core Point)ε 邻域内样本数 ≥ min_samples 的点
边界点(Border Point)ε 邻域内样本数 < min_samples,但落在某个核心点的 ε 邻域内的点
噪声点(Noise Point)既不是核心点也不是边界点的点(标签为 -1)

2.3 簇的定义与连接

DBSCAN 的簇由密度相连的核心点及其边界点组成:

  • 直接密度可达:点 q 在核心点 p 的 ε 邻域内,则 q 从 p 直接密度可达
  • 密度可达:通过一串核心点,从 p 可以“接力”到达 q,则 q 从 p 密度可达
  • 密度相连:存在点 o,使得 p 和 q 都从 o 密度可达,则 p 和 q 密度相连

一个簇就是所有密度相连的点的最大集合

通俗理解:核心点就像“感染源”,它会把 ε 邻域内的所有点拉入同一个簇。如果这个簇里有其他核心点,它们又会继续向外“感染”更多的点。直到遇到“边界点”或“噪声点”,传播才停止。

2.4 算法流程

  1. 随机选择一个未访问的数据点
  2. 检查该点的 ε 邻域:
    • 如果邻域内点数 ≥ min_samples,标记为核心点,邻域内所有点加入同一簇
    • 否则标记为噪声(但之后如果被核心点纳入邻域,可能转为边界点)
  3. 对簇内的核心点,递归扩展其邻域,将更多点加入簇
  4. 重复 1-3 步,直到所有点都被访问

三、DBSCAN vs K-Means

对比维度K-MeansDBSCAN
是否需指定 K是,必须预先指定,自动发现簇
簇的形状只能发现凸形(球形)簇可发现任意形状的簇
噪声处理所有点都被分配,无噪声概念自动识别噪声点(标签 -1)
参数依赖主要依赖 K 值依赖 eps 和 min_samples,较敏感
密度差异对密度差异不敏感对密度差异大的数据表现不佳

四、DBSCAN 的优缺点

4.1 优点

  1. 无需预设簇数量:自动根据密度划分簇
  2. 支持任意形状的簇:可识别环形、S 形、不规则形状的簇
  3. 能识别噪声点:天然支持离群点检测
  4. 对数据顺序不敏感:聚类结果稳定

4.2 缺点

  1. 对参数 eps 和 min_samples 敏感:参数选择不当会导致聚类结果差异极大
  2. 不适合密度差异大的数据:同一套参数无法同时适配高密度和低密度区域
  3. 高维数据效果差:高维空间中“距离”概念失效,需先降维
  4. 大规模数据效率较低:传统实现时间复杂度为 O(n²)

五、典型应用场景

  • 图像分割:将图片中的不同区域(如森林、湖泊)分割成不同的簇
  • 社交网络分析:识别不同的用户群体或社区
  • 异常检测:远离所有簇的样本点可能是异常点
  • 地理空间数据:GPS 轨迹聚类、犯罪热点分析
  • 文本挖掘:将相似文档归为一组

六、核心 API 速查

6.1 导包方式

fromsklearn.clusterimportDBSCAN

6.2 核心参数详解

参数名类型默认值说明
epsfloat0.5邻域半径。最重要的参数,决定邻居的距离阈值。eps 过大会合并不同的簇,过小会拆分同一个簇
min_samplesint5核心点密度阈值。eps 一定时,min_samples 过大会导致核心点过少,噪声增多;过小会产生大量核心点,簇数减少
metricstr'euclidean'距离度量方式。常用'euclidean'(欧氏距离)、'manhattan'(曼哈顿距离)
algorithmstr'auto'近邻搜索算法。'auto'自动选择,'kd_tree''ball_tree''brute'
leaf_sizeint30KD树或球树的叶子节点大小,影响建树和查询速度

6.3 常用属性

属性名说明
core_sample_indices_核心点的索引
components_所有核心点的坐标
labels_每个样本的簇标签,-1 表示噪声点

6.4 常用方法

方法名说明
fit(X)训练模型
fit_predict(X)训练并返回每个样本的簇标签(噪声点为 -1)

七、实战案例:啤酒聚类分析

7.1 案例背景

在 K-Means 篇中,我们将 20 种啤酒按热量、钠含量、酒精浓度、价格聚成了 4 类。本篇尝试用 DBSCAN 对同样的数据进行分析,对比两种算法的聚类结果。

7.2 数据说明

字段含义单位
calories热量卡路里
sodium钠含量毫克
alcohol酒精浓度体积百分比
cost价格美元

数据示例:

品牌热量钠含量酒精浓度价格
Budweiser144154.70.43
Schlitz151194.90.43
Lowenbrau157150.90.48
Kronenbourg17075.20.73
Heineken152115.00.77

7.3 完整代码

importpandasaspdimportnumpyasnpfromsklearn.clusterimportDBSCANfromsklearn.preprocessingimportMinMaxScalerfromsklearn.metricsimportsilhouette_scoreimportmatplotlib.pyplotasplt# ===================设置中文字体=========================plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=False# ===================读取数据=========================beer=pd.read_table("data.txt",sep=' ',encoding='utf-8',engine='python')X=beer[['calories','sodium','alcohol','cost']]# ===================01标准化=========================scaler=MinMaxScaler()X_scaled=scaler.fit_transform(X)# ===================网格搜索=========================eps_values=np.arange(0.1,1.0,0.1)# 邻域半径候选值min_samples_values=range(2,7)# 最小样本数候选值results=[]print("===== 网格搜索 =====")forepsineps_values:formin_samplesinmin_samples_values:labels=DBSCAN(eps=eps,min_samples=min_samples).fit_predict(X_scaled)n_clusters=len(set(labels))-(1if-1inlabelselse0)# 簇数(排除噪声)n_noise=list(labels).count(-1)# 噪声点数ifn_clusters>=2:# 至少2个簇才能计算轮廓系数score=silhouette_score(X_scaled,labels)results.append({'eps':eps,'min_samples':min_samples,'n_clusters':n_clusters,'n_noise':n_noise,'score':score})print(f"eps={eps:.1f}, min_samples={min_samples}: 簇数={n_clusters}, 噪声={n_noise}, 轮廓系数={score:.4f}")# ===================最优参数=========================ifresults:best=max(results,key=lambdax:x['score'])# 选轮廓系数最大的print(f"\n最优参数: eps={best['eps']:.1f}, min_samples={best['min_samples']}")print(f"最优轮廓系数:{best['score']:.4f}")best_labels=DBSCAN(eps=best['eps'],min_samples=best['min_samples']).fit_predict(X_scaled)beer['cluster']=best_labelsprint(f"\n簇数:{best['n_clusters']}")print(f"噪声点:{best['n_noise']}")print("\n各簇包含的品牌:")forcidinsorted(beer['cluster'].unique()):brands=beer[beer['cluster']==cid]['name'].tolist()ifcid==-1:print(f"噪声点:{', '.join(brands)}")else:print(f"簇{cid}{len(brands)}种):{', '.join(brands)}")else:print("\n未找到有效的聚类组合")
===== 网格搜索 ===== eps=0.2, min_samples=2: 簇数=3, 噪声=12, 轮廓系数=0.0281 eps=0.3, min_samples=2: 簇数=3, 噪声=6, 轮廓系数=0.2266 eps=0.3, min_samples=3: 簇数=3, 噪声=6, 轮廓系数=0.2266 eps=0.3, min_samples=4: 簇数=2, 噪声=9, 轮廓系数=0.1283 eps=0.4, min_samples=2: 簇数=2, 噪声=2, 轮廓系数=0.3162 eps=0.4, min_samples=3: 簇数=2, 噪声=2, 轮廓系数=0.3162 eps=0.4, min_samples=4: 簇数=2, 噪声=2, 轮廓系数=0.3162 eps=0.5, min_samples=2: 簇数=2, 噪声=1, 轮廓系数=0.3435 eps=0.5, min_samples=3: 簇数=2, 噪声=1, 轮廓系数=0.3435 eps=0.5, min_samples=4: 簇数=2, 噪声=1, 轮廓系数=0.3435 最优参数: eps=0.5, min_samples=2 最优轮廓系数: 0.3435 簇数: 2 噪声点: 1 各簇包含的品牌: 噪声点: Lowenbrau 簇 0(15 种): Budweiser, Schlitz, Old_Milwaukee, Augsberger, Srohs_Bohemian_Style, Miller_Lite, Budweiser_Light, Coors, Coors_Light, Michelob_Light, Pabst_Extra_Light, Hamms, Heilemans_Old_Style, Olympia_Goled_Light, Schlitz_Light 簇 1(4 种): Kronenbourg, Heineken, Becks, Kirin

7.4 关键步骤说明

步骤说明
数据标准化DBSCAN 基于距离计算,特征尺度不同会影响结果,需先标准化
参数探索尝试不同的 eps 值,观察簇数和噪声点的变化,选择合适参数
DBSCAN 聚类使用最优 eps 和 min_samples 进行聚类

八、总结

核心知识点速查

知识点关键概念
DBSCAN基于密度的聚类,发现任意形状的簇
核心点ε 邻域内样本数 ≥ min_samples
边界点邻域内样本不足,但落在核心点的邻域内
噪声点既非核心点也非边界点(标签 -1)
eps邻域半径,最关键参数
min_samples核心点的密度阈值

核心 API 一览

用途对应模块 / 方法
模型sklearn.cluster.DBSCAN
训练并返回标签fit_predict(X)
核心点索引core_sample_indices_
簇标签(-1 为噪声)labels_
轮廓系数sklearn.metrics.silhouette_score

注意事项

要点说明
特征必须标准化DBSCAN 基于距离,特征尺度不同会严重影响结果
eps 选择过小:簇被拆分,噪声增多;过大:簇被合并
min_samples 选择通常设为维度 + 1(如二维数据设 3)
密度差异大同一套参数无法适配高密度和低密度区域

系列直达

  • 上篇:机器学习入门:K-Means 聚类
  • 本篇:机器学习入门:DBSCAN 聚类(本文)
  • 下篇:敬请期待
← 返回列表