DBSCAN算法

article/2025/8/24 13:54:53

本文简单介绍DBSCAN算法的原理及实现。

DBSCAN算法原理

基本概念

DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的空间聚类算法。该算法将具有足够密度的区域划分为簇,并在具有噪声的空间数据库中发现任意形状的簇,它将簇定义为密度相连的点的最大集合。

假设样本集为 D = ( x 1 , x 2 , . . . , x m ) D=(x_1, x_2, ..., x_m) D=(x1,x2,...,xm),DBSCAN算法有如下相关定义:

  • ϵ \epsilon ϵ-邻域:对于 x j ∈ D x_j∈D xjD,其 ϵ \epsilon ϵ-邻域包含样本集 D D D中与 x j x_j xj的距离不大于 ϵ \epsilon ϵ的子样本集,即 N ϵ ( x j ) = { x i ∈ D ∣ d i s t a n c e ( x i , x j ) ⩽ ϵ } , N_{\epsilon}(x_j)= \{x_i∈D|distance(x_i,x_j) \leqslant \epsilon \}, Nϵ(xj)={xiDdistance(xi,xj)ϵ}, 这个子样本集的个数记为 ∣ N ϵ ( x j ) ∣ |N_{\epsilon}(x_j)| Nϵ(xj)
  • 核心点:对于任一样本 x j ∈ D x_j∈D xjD,如果其ϵϵ-邻域对应的 N ϵ ( x j ) N_{\epsilon}(x_j) Nϵ(xj)至少包含 M i n P t s MinPts MinPts个样本,即如果 ∣ N ϵ ( x j ) ∣ ≥ M i n P t s |N_{\epsilon}(x_j)|≥MinPts Nϵ(xj)MinPts,则 x j x_j xj是核心对象。
  • 密度直达:如果 x i x_i xi位于 x j x_j xj ϵ \epsilon ϵ-邻域中,且 x j x_j xj是核心对象,则称 x i x_i xi x j x_j xj密度直达。
  • 密度可达:对于 x i x_i xi x j x_j xj,如果存在样本样本序列 p 1 , p 2 , . . . , p T p_1,p_2,...,p_T p1,p2,...,pT,满足 p 1 = x i , p T = x j p_1=x_i,pT=x_j p1=xi,pT=xj, 且 p t + 1 p_{t+1} pt+1 p t p_t pt密度直达,则称 x j x_j xj x i x_i xi密度可达。
  • 密度相连:对于 x i x_i xi x j x_j xj,如果存在核心对象样本 x k x_k xk,使 x i x_i xi x j x_j xj均由 x k x_k xk密度可达,则称 x i x_i xi x j x_j xj密度相连。

注意:

  • 密度直达是非对称的,若 x i x_i xi x j x_j xj密度直达,只有当 x i x_i xi也为核心对象时,才有 x j x_j xj x i x_i xi密度直达
  • 密度可达是密度直达的传递闭包,是非对称的
  • 密度相连是对称的

算法原理

总体思路

  1. 遍历每一个未处理的点
    1. 如果为核心点,找出所有从该点密度可达的点,形成一个簇
    2. 否则,标记后遍历下一个点

详细算法

算法1

输入:样本集 D = ( x 1 , x 2 , . . . , x m ) D=(x_1, x_2, ..., x_m) D=(x1,x2,...,xm),参数 ( ϵ , M i n P t s ) (\epsilon, MinPts) (ϵ,MinPts)

输出:核心点集合 Ω \Omega Ω

  1. 初始化核心对象集合 Ω = ∅ \Omega = \emptyset Ω=
  2. 对于所有点 x j x_j xj:
    1. 找到样本 x j x_j xj ϵ \epsilon ϵ-邻域子样本集 N ϵ ( x j ) N_{\epsilon}(x_j) Nϵ(xj)
    2. 如果子样本集合个数满足 ∣ N ϵ ( x j ) ∣ ≥ M i n P t s |N_{\epsilon}(x_j)|≥MinPts Nϵ(xj)MinPts,将样本 x j x_j xj加入核心对象样本集合 Ω = Ω ∪ { x j } \Omega = \Omega \cup \{ x_j \} Ω=Ω{xj}

算法2

输入:样本集 D = ( x 1 , x 2 , . . . , x m ) D=(x_1, x_2, ..., x_m) D=(x1,x2,...,xm),参数 ( ϵ , M i n P t s ) (\epsilon, MinPts) (ϵ,MinPts)

输出:簇划分结果 C = { C 1 , C 2 , . . . , C k } C=\{ C_1, C_2, ..., C_k \} C={C1,C2,...,Ck}

  1. 执行算法1,找到所有核心点 Ω \Omega Ω
  2. 初始化簇类别 k = 0 k=0 k=0, 未访问样本集合 Γ = D \Gamma = D Γ=D, 簇划分结果 C = ∅ C=\emptyset C=
  3. 如果核心点集合 Ω \Omega Ω不为空,则继续执行,否则算法结束
  4. 在核心对象集合 Ω \Omega Ω中,随机选择一个核心对象 o o o,初始化当前簇核心对象队列 Ω c u r = { o } Ω_{cur}=\{o\} Ωcur={o},初始化当前簇样本集合 C k = { o } C_k=\{o\} Ck={o}, 更新未访问样本集合 Γ = Γ − o Γ=Γ−{o} Γ=Γo
  5. Repeat
  6. 如果当前簇核心对象集合 Ω c u r ≠ ∅ Ω_{cur}\ne∅ Ωcur=,在 Ω c u r Ω_{cur} Ωcur中取出一个核心对象 o ′ o′ o,通过邻域距离阈值 ϵ ϵ ϵ找出所有的 ϵ ϵ ϵ-邻域子样本集 N ϵ ( o ′ ) N_ϵ(o′) Nϵ(o),令 Δ = N ϵ ( o ′ ) ∩ Γ Δ=N_ϵ(o′)∩Γ Δ=Nϵ(o)Γ, 更新当前簇样本集合 C k = C k ∪ Δ C_k=C_k∪Δ Ck=CkΔ, 更新未访问样本集合 Γ = Γ − Δ Γ=Γ−Δ Γ=ΓΔ, 更新 Ω c u r = Ω c u r ∪ ( Δ ∩ Ω ) − o ′ Ω_{cur}=Ω_{cur}∪(Δ∩Ω)−o′ Ωcur=Ωcur(ΔΩ)o,更新核心对象集合 Ω = Ω − C k Ω=Ω−C_k Ω=ΩCk
  7. 如果当前簇核心对象队列 Ω c u r = ∅ Ω_{cur}=∅ Ωcur=,则当前聚类簇 C k C_k Ck生成完毕, 更新簇划分 C = C ∪ C k C=C \cup C_k C=CCk k = k + 1 k=k+1 k=k+1,转入步骤3。

DBSCAN算法实现

Sklearn DBSCAN

尝试使用sklearn中的DBSCAN算法。

# all import
from sklearn import datasets
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
import numpy as np
import time
# generate data
n_samples = 1500
noisy_circles = datasets.make_circles(n_samples=n_samples, factor=.5,noise=.05)
X, y = noisy_circles
# plot
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
# plt.figure(1)
plt.scatter(X[:, 0], X[:, 1])plt.subplot(1, 2, 2)
# plt.figure(2)
plt.scatter(X[:, 0], X[:, 1], c=y)

请添加图片描述

上图是sklearn生成的数据,右图是根据label直接绘制的结果。

下面使用sklearn中的DBSCAN类对数据X进行聚类。

# run sklearn DBSCAN to predict
y_pred = DBSCAN(eps=0.1).fit_predict(X)# plot sklearn DBSCAN result
plt.figure(figsize=(5, 5))
plt.scatter(X[:, 0], X[:, 1], c=y_pred)

在这里插入图片描述

My DBSCAN

此部分代码为笔者依据上述伪代码实现,未经过优化

# my DBSCAN algorithm
from sklearn.metrics.pairwise import pairwise_distancesclass MyDBSCAN:def __init__(self, X, eps=0.5, minPts=5):"""@param:X: input dataset, (n, m)eps: minPts:"""self.X = Xself.n = len(X)self.eps = epsself.minPts = minPtsdef get_core_points(self):"""@return:core_points: the index of core points"""core_points = []for i in range(self.n):neighbors = self.get_neighbors(i)if len(neighbors) >= self.minPts:core_points.append(i)return core_pointsdef get_neighbors(self, point_idx):"""@param:point_idx: index of point@return:neighbors: neighbors of point"""neighbors = []for i in range(self.n):if self.dis_mat[point_idx][i] < self.eps:neighbors.append(i)return neighborsdef compute_dis_mat(self):"""@param:X: input dataset, (n, m)@return:self.dis_mat: (n, n)"""self.dis_mat = pairwise_distances(X)returndef random_choose(self, points):"""random choose a point"""# return points[0]return points[np.random.randint(0, len(points))]def fit_predict(self):"""@param:X: input dataset, (n, m)@return:y_pred: predicted result, (n,)"""# computer distance matrixself.compute_dis_mat()core_points = set(self.get_core_points())waiting_points = set([i for i in range(len(self.X))])cluster = -1 * np.ones(self.n, dtype=np.int32)k = 0while len(core_points) > 0:o = self.random_choose(list(core_points))cur_core_points = set()cur_core_points.add(o)cur_cluster = set()cur_cluster.add(o)waiting_points.remove(o)while True:if len(cur_core_points) > 0:point = list(cur_core_points)[0]neighbors = set(self.get_neighbors(point))delta = neighbors & waiting_pointscur_cluster = cur_cluster | deltawaiting_points = waiting_points - deltacur_core_points = cur_core_points | (delta & core_points)cur_core_points.remove(point)core_points = core_points - cur_clusterelse:cluster[list(cur_cluster)] = kk += 1breakreturn cluster

将其用到sklearn生成的数据集上测试效果:

n_samples = 500
noisy_circles = datasets.make_circles(n_samples=n_samples, factor=.5,noise=.05)
X, y = noisy_circles
start = time.time()
y_my_pred = MyDBSCAN(X=X, eps=0.15).fit_predict()
end1 = time.time()
y_pred = DBSCAN(eps=0.15).fit_predict(X)
end2 = time.time()print('{:15} {:5} {:3}'.format('Algorithm', 'Time', 'NMI'))
print('{:15} {:5.2f} {:3}'.format('My DBSCAN ', end1 - start, metrics.normalized_mutual_info_score(y, y_my_pred)))
print('{:15} {:5.2f} {:3}'.format('Sklearn DBSCAN', end2 - end1, metrics.normalized_mutual_info_score(y, y_pred)))
Algorithm       Time  NMI
My DBSCAN       0.11  1.0
Sklearn DBSCAN  0.00  1.0
# plot sklearn DBSCAN result
plt.figure(figsize=(15, 5))
plt.subplot(1, 3, 1)
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.title('origin data')plt.subplot(1, 3, 2)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.title('sklearn DBSCAN')plt.subplot(1, 3, 3)
plt.scatter(X[:, 0], X[:, 1], c=y_my_pred)
plt.title('My DBSCAN')

在这里插入图片描述

修改eps后的测试结果(minPts=5):

epsresult
0.1在这里插入图片描述
0.12在这里插入图片描述
0.15在这里插入图片描述

可以观察到在sklearn生成的该类数据集上My DBSCAN与sklearn DBSCAN的聚类结果非常接近,但My DBSCAN的运行时间较长。

Reference

A Density-Based Algorithm for Discovering Clusters in Large Spatial Databases with Noise (aaai.org)

DBSCAN密度聚类算法 - 刘建平Pinard - 博客园

用scikit-learn学习DBSCAN聚类 - 刘建平Pinard - 博客园

DBSCAN - 维基百科

详解DBSCAN聚类 - 知乎

Visualizing DBSCAN Clustering


http://chatgpt.dhexx.cn/article/VM7G8vWn.shtml

相关文章

DBSCAN点云聚类

1、DBSCAN算法原理 DBSCAN是一种基于密度的聚类方法&#xff0c;其将点分为核心点与非核心点&#xff0c;后续采用类似区域增长方式进行处理。下图为DBSCAN聚类结果&#xff0c;可见其可以对任意类别的数据进行聚类&#xff0c;无需定义类别数量。 DBSCAN聚类说明 DBSCAN聚类过…

DBSCAN

DBSCAN 算法将具有足够高密度的区域划分为簇&#xff0c;并可 以发现任何形状的聚类 DBSCAN算法概念 &#x1d6c6;邻域&#xff1a;给定对象半径&#x1d700;内的区域称为该对象的&#x1d700;邻域。核心对象&#xff1a;如果给定 &#x1d700; 邻域内的样本点数大于等于M…

密度聚类之DBSCAN算法原理

DBSCAN(Density-Based Spatial Clustering of Applications with Noise&#xff0c;具有噪声的基于密度的聚类方法)是一种很典型的密度聚类算法&#xff0c;和K-Means&#xff0c;BIRCH这些一般只适用于凸样本集的聚类相比&#xff0c;DBSCAN既可以适用于凸样本集&#xff0c;也…

总结:机器学习之DBSCAN

一、基本思想 DBSCAN是一种基于密度的聚类算法&#xff0c;这类密度聚类算法一般假定类别可以通过样本分布的紧密程度决定。同一类别的样本&#xff0c;他们之间的紧密相连的&#xff0c;也就是说&#xff0c;在该类别任意样本周围不远处一定有同类别的样本存在。 通过将紧密…

聚类算法也可以异常检测?DBSCAN算法详解。

一、算法概述 DBSCAN是一个出现得比较早&#xff08;1996年&#xff09;&#xff0c;比较有代表性的基于密度的聚类算法&#xff0c;虽然这个算法本身是密度聚类算法&#xff0c;但同样可以用作异常检测&#xff0c;其思想就是找到样本空间中处在低密度的异常样本&#xff0c;本…

DBSCAN详解

一、基本概念 DBSCAN的基本概念可以用1&#xff0c;2&#xff0c;3&#xff0c;4来总结。 1个核心思想&#xff1a;基于密度 直观效果上看&#xff0c;DBSCAN算法可以找到样本点的全部密集区域&#xff0c;并把这些密集区域当做一个一个的聚类簇。 2个算法参数&#xff1a;邻…

【机器学习】DBSCAN聚类算法

DBSCAN聚类算法 DBSCAN&#xff08;Density-Based Spatial Clustering of Applications with Noise&#xff0c;具有噪声的基于密度的聚类方法&#xff09;是一种基于密度的空间聚类算法。 1.基本概念 核心对象:若某个点的密度达到算法设定的阈值则其为核心点。(即r的 ϵ \e…

30款APP源码打包 Java Android安卓App源码 30款打包下载

[30款APP源码打包 Java Android安卓App源码 30款打包下载](访问密码: 168168)(https://474b.com/file/29013429-461457489)

【Android】Android源码下载

学而不思则罔&#xff0c;思而不学则殆 【Android】Android源码下载 一.环境准备虚拟机Ubuntu系统 二.Android源码下载Ubuntu下载1.repo下载2.修改源代码镜像地址3.初始化仓库4.指定版本5.同步源码树 Windows下载1.repo下载2.修改源代码镜像地址3.初始化仓库4.指定版本5.同步源…

下载Android源码流程(完整版)

要在Linux环境下操作&#xff0c;要在Linux环境下操作&#xff0c;要在Linux环境下操作~~ 不要想在Windows环境下操作&#xff0c;因为会有各种问题。Windows环境的童鞋又不想装双系统的可以跟着下面的操作&#xff0c;Linux的童鞋可以直接跳过看。Mac的童鞋就略过~~~ &#x…

Android系统源码下载

1&#xff0c;ubuntu电脑 2&#xff0c;下载 repo 工具: mkdir ~/bin PATH~/bin:$PATH curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo chmod ax ~/bin/repo3&#xff0c; 建立工作目录: mkdir WORKING_DIRECTORY cd WORKING_DIRECTORY4&am…

Android系统源码_下载编译——从下载系统源码到编译系统镜像

前言 近期因工作原因&#xff0c;需要频繁编译、调试Android源码 &#xff0c;特别是修改framework层的源码&#xff0c;经过不懈努力&#xff0c;终于可以正常调试了。 这里进行一些总结和分享。 参考文章&#xff1a;清华镜像之Android 镜像使用帮助、Android系统源码编译 …

下载并编译Android源码

下载编译源码 系统架构&#xff1a; Linux&#xff1a;Linux内核和驱动模块&#xff08;USB Camera 蓝牙等&#xff09; Libraries&#xff1a;提供动态库&#xff0c;Android运行时库、Dalvik虚拟机等&#xff0c;大部分是C 和C写的&#xff0c;可以看成是native层 Framewo…

一、安卓系统源码下载

前言&#xff1a;为了研究安卓系统&#xff0c;我们需要下载安卓源码&#xff0c;本篇博文参考安卓官网https://source.android.com &#xff0c;对安卓系统各个版本源码的下载做出了详细解释。 一、环境要求概览 在下载编译安卓系统源码前&#xff0c;我们必须对各个版本安卓…

从github下载最新Android源码

今年5月底开始&#xff0c;谷歌彻底被墙&#xff0c;所有谷歌的网站都不能访问了&#xff0c;这次包括了android.org&#xff0c;googlesource.com&#xff0c;code.google.com。Android官方的资源不能访问&#xff0c;想下载Android代码当然是困难重重了。 本文就为大家解决这…

Android源码下载编译(TI)

0 前言 通过《Android源码下载 & 编译&#xff08;高通&#xff09;》的方法下载的源码是包含有kernel目录的&#xff08;也就是包含Linux内核&#xff09;&#xff0c;然而&#xff0c;通过其它方法下载的源码可能并不包含kernel目录&#xff08;也就是不包含Linux内核&am…

安卓系统源码、内核下载

一、下载源码 以下载源码2.3.7版本为例 环境ubuntu14.04 1、安装git sudo apt-get install git git --version //查看版本 git config --global user.name "zhangsan" //设置用户名 git config --global user.email "zhangsan163.com" //设置邮箱 git…

AOSP安卓源码下载

Android源码下载 在国内想下载Android要么科学上网&#xff0c;要么使用国内搭建的镜像&#xff0c;有清华镜像&#xff0c;中科大的镜像网站。这里使用清华镜像网站镜像Android源码的下载清华镜像网站地址&#xff0c;为啥我要写这篇笔记嘞&#xff0c;虽然网上有很多这方便的…

安卓系统源码编译系列(一)——下载安卓系统源码教程

最近需要编译安卓系统&#xff0c;咨询了一个编译过安卓系统的朋友&#xff0c;说是下载源码就得下载两天&#xff0c;于是做好了长期抗战的准备&#xff0c;开始了下载安卓源码的旅程。在刚开始下载时&#xff0c;可以参照的内容只有官方教程&#xff0c;于是跟着官方教程一步…

【Android】系统源码下载及编译

源码及编译 步骤 1&#xff1a;创建一个空目录来存放源码&#xff1a; mkdir aosp cd aosp步骤 2&#xff1a;获取最新版本的 repo 并签出 android-8.1.0_r1 分支&#xff1a; repo init -u https://android.googlesource.com/platform/manifest -b android-8.1.0_r1其中&am…