DBSCAN 密度聚类
从核心点扩展高密度区域,识别任意形状簇并把孤立样本标为噪声。
学习前需要掌握
背景与问题
K-Means 会把每个点分配给某个中心,孤立异常也必须入组。若希望允许噪声点、发现弯曲的高密度区域,可以改从局部邻域连接出发;DBSCAN 的难点转为距离尺度与密度阈值选择。
概念定义
DBSCAN 以 eps 半径内的样本数判断核心点,scikit-learn 的 min_samples 包含样本自身。相连核心点及其邻域形成簇,靠近核心点但自身密度不足的是边界点,其余为噪声,常标为 −1。它无需预先给簇数,但并非无需参数。
直观理解
人群中的密集站点能继续把相邻人群连接起来,边缘围观者可以加入,却不能仅靠一条稀疏人链无限扩张。核心点和边界点的不同作用决定了扩张边界。
核心原理
从一个核心点扩展时,遇到其他核心点可以继续扩张;仅有边界点不能作为新的扩张源。先被标记为噪声的点若后来进入核心邻域,可以成为边界点,因此一次暂定噪声不是不可撤销的真值。
eps 依赖距离单位与特征尺度,min_samples 表示局部支持需求。统一阈值难同时适应密度差异很大的簇,高维距离集中也会削弱邻域判断;缩放和度量选择需要任务解释。
噪声标签不是异常真实标签,可能只是阈值下未连接的正常小群体。边界点同时邻近两个簇时,归属可能受遍历顺序影响;评测还需报告噪声比例与覆盖,不能只把噪声删掉后展示漂亮簇。
数学表达
eps 邻域与核心条件
本页沿用包含自身的样本计数,m 为 min_samples;有样本权重时实现可使用加权条件。
变量含义
变量定义与本页概念定义一致,代码中的同名变量保持相同语义。
计算步骤
- 1确定特征尺度与距离度量,检查邻域语义。
- 2选择 eps 与 min_samples,明确是否包含自身。
- 3识别核心点,从未访问核心点扩展密度连接区域。
- 4加入核心邻域的边界点,不通过单独边界继续扩张。
代码对应位置
示例 1区分核心点、边界点和噪声:完整指定一维数据与参数,核对 min_samples 包含自身。
手算与场景核对
一维点为 0、0.1、0.2、0.3、1,eps=0.11,min_samples=3。点 0.1 的邻域含 0、0.1、0.2,点 0.2 的邻域含 0.1、0.2、0.3,它们是核心点。
点 0 与 0.3 自己只各有两个邻居计数,却紧邻核心点,因此是边界点;点 1 孤立,标为噪声。前四个点成一簇,只有中间两个点是核心。
计算与实现步骤
- 确定特征尺度与距离度量,检查邻域语义。
- 选择 eps 与 min_samples,明确是否包含自身。
- 识别核心点,从未访问核心点扩展密度连接区域。
- 加入核心邻域的边界点,不通过单独边界继续扩张。
- 标记剩余噪声,比较参数敏感性、覆盖率与业务解释。
代码实现
示例 1
区分核心点、边界点和噪声
example_01.py用途:完整指定一维数据与参数,核对 min_samples 包含自身。
import numpy as np
from sklearn.cluster import DBSCAN
X = np.array([[0.0], [0.1], [0.2], [0.3], [1.0]])
model = DBSCAN(eps=0.11, min_samples=3).fit(X)
core = set(model.core_sample_indices_.tolist())
boundary = [i for i, label in enumerate(model.labels_) if label != -1 and i not in core]
print("labels=" + ",".join(map(str, model.labels_)))
print(f"core={sorted(core)}, boundary={boundary}")
print("noise=" + str(np.flatnonzero(model.labels_ == -1).tolist()))代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
完整指定一维数据与参数,核对 min_samples 包含自身。
X- 完整特征矩阵,每行一个样本、每列一个特征。
model- 组合预处理和估计器的模型对象。
Step 1 · 1–2 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
import numpy as np
from sklearn.cluster import DBSCANStep 2 · 4–10 行
调用 fit 学习训练数据中的参数;若在 Pipeline 中,预处理器与模型会按顺序拟合。
X = np.array([[0.0], [0.1], [0.2], [0.3], [1.0]])
model = DBSCAN(eps=0.11, min_samples=3).fit(X)
core = set(model.core_sample_indices_.tolist())
boundary = [i for i, label in enumerate(model.labels_) if label != -1 and i not in core]
print("labels=" + ",".join(map(str, model.labels_)))
print(f"core={sorted(core)}, boundary={boundary}")
print("noise=" + str(np.flatnonzero(model.labels_ == -1).tolist()))预期输出或运行结果
labels=0,0,0,0,-1 core=[1, 2], boundary=[0, 3] noise=[4]
常见错误 · 3 条
- min_samples 计数时漏掉自身,导致核心点集合错误。
- 允许边界点无限扩张,把稀疏链连成一簇。
- 把 −1 直接当作已证实的异常或欺诈标签。
实际应用
- 寻找可能非球形的高密度区域,同时允许未分配点。
- 作为探索性噪声筛查,但仍需要独立异常定义。
常见错误
- min_samples 计数时漏掉自身,导致核心点集合错误。
- 允许边界点无限扩张,把稀疏链连成一簇。
- 把 −1 直接当作已证实的异常或欺诈标签。
资料与假设
参见 scikit-learn:DBSCAN。 本页数值均为构造例;涉及模型分数时仅说明给定数据与协议下的计算。
推荐学习资料
参考库不会生成虚假资源或无效外部链接。