DBSCAN算法 简单实现 二维/三维结果展示

简介

参考:
https://en.wikipedia.org/wiki/DBSCAN
https://www.cnblogs.com/pinard/p/6208966.html

DBSCAN(Density-based spatial clustering of applications with noise) 最常用的聚类分析算法之一。
该算法以密度为本:给定某空间里的一个点,这算法能把该点附近的点集合成一类(有很多相邻点的点 即高密度区域),并标记出位于低密度区域的局外点(噪音点,最接近它的点也十分远)。


基础知识

DBSCAN 需要两个参数:ε (eps) 和形成高密度区域所需要的最少点数** MinPts**
为了进行 DBSCAN 聚类,所有的点被分为核心点(密度)可达点局外点

  • ε (eps)
    邻域的范围,即在以点p为中心,ε 为半径的圆为p的邻域
  • MinPts(领域密度阈值)
    判定为核心点(下文解释)邻域内需要的点数(包括自身)
  • 直接可达
    核心点p邻域内的点被称为由 p 直接可达。同时定义,没有任何点是由非核心点直接可达的
  • 核心点
    如果一个点 p 在距离 ε 范围内有至少 minPts 个点(包括自己),则这个点被称为核心点
  • 密度可达点
    如果存在一条道路 p1, …, pn ,有 p1 = p和pn = q, 且每个 pi+1 都是由 pi 直接可达的(道路上除了 q 以外所有点都一定是核心点),则称 q 是由 p 可达的
  • 局外点(噪音)
    不由任何点可达的点都被称为局外点

注意:“可达性”(英文:Reachability )不是一个对称关系,因为根据定义,没有点是由非核心点可达的,但非核心点可以是由其他点可达的。所以为了正式地界定 DBSCAN 找出的聚类,进一步定义两点之间的“连结性”(英文:Connectedness) :如果存在一个点 o 使得点 p 和点 q 都是由 o 可达的,则点 p 和点 q 被称为(密度)连结的,而连结性是一个对称关系。


在上图中,minPts = 4,点 A 和其他红色点是核心点,因为它们的 ε-邻域(图中红色圆圈)里包含最少 4 个点(包括自己),由于它们之间相互相可达,它们形成了一个聚类。点 B 和点 C 不是核心点,但它们可由 A 经其他核心点可达,所以也属于同一个聚类。点 N 是局外点,它既不是核心点,又不由其他点可达

总结
如果 p 是核心点,则它与所有由它可达的点(包括核心点和非核心点)形成一个聚类,每个聚类拥有最少一个核心点,非核心点也是聚类的一部分,但它是在聚类的“边缘”位置,因为它不能达至更多的点


算法过程

由一个任意未被访问的点开始,然后探索这个点的 ε-邻域,如果 ε-邻域里有足够的点,则建立一个新的聚类,否则这个点被标签为杂音。注意这个点之后可能被发现在其它点的 ε-邻域里,而该 ε-邻域可能有足够的点,届时这个点会被加入该聚类中。

如果一个点位于一个聚类的密集区域里,它的 ε-邻域里的点也属于该聚类,当这些新的点被加进聚类后,如果它(们)也在密集区域里,它(们)的 ε-邻域里的点也会被加进聚类里。这个过程将一直重复,直至不能再加进更多的点为止,这样,一个密度连结的聚类被完整地找出来。然后,一个未曾被访问的点将被探索,从而发现一个新的聚类或杂音。
在这里插入图片描述


代码实现

简单实现 为了方便不再随机挑选点 先将所有核心点挑选出来遍历 未访问到的就是局外点

# -*- coding: utf-8 -*-
"""
Created on Wed Apr 15 16:08:51 2020

@author: alpha
"""

import numpy as np
import matplotlib.pyplot as plt

size = 30

##计算欧式距离
def distEuclid(x,y):
    return np.sqrt(np.sum((x-y)**2))

##随机产生n个dim维度的数据 (这里为了展示结果 dim取2或者3)
def genDataset(n,dim):
    data = []
    while len(data)<n:
        p = np.around(np.random.rand(dim)*size,decimals=2)
        data.append(p)
    return data

##判断两点是否在范围内
def isNeighbor(x,y,eps):
    return distEuclid(x,y)<=eps

##获取某一点邻域内的点
def getSeedPos(pos,data,eps):
    seed = []
    for p in range(len(data)):
        if isNeighbor(data[p],data[pos],eps):
            seed.append(p)
    return seed

##获取核心点列表
def getCorePointsPos(data,eps,minpts):
    cpoints=[]
    for pos in range(len(data)):
        if len(getSeedPos(pos,data,eps))>=minpts:
            cpoints.append(pos)
    return cpoints

##分类
def getCluster(data,eps,minpts):
    corePos = getCorePointsPos(data,eps,minpts)
    unvisited =list(range(len(data)))
    cluster = {}
    num = 0
    
    for pos in corePos:
        if pos not in unvisited:
            continue
        clusterpoint = []
        clusterpoint.append(pos)
        seedlist = getSeedPos(pos,data,eps)
        unvisited.remove(pos)
        while seedlist:
            p = seedlist.pop(0)
            if p not in unvisited:
                continue
            unvisited.remove(p)
            clusterpoint.append(p)
            if p in corePos:
                seedlist.extend(getSeedPos(p,data,eps))
        cluster[num] = clusterpoint    
        num+=1
    cluster["noisy"]=unvisited
    return cluster

##展示结果  各类簇使用不同的颜色  中心点使用X表示
def Show(data,cluster):
    num,dim = data.shape
    color = ['r','g','c','y','m','b','pink','maroon','tomato','peru','lawngreen','gold','aqua','dodgerblue']
    ##二维图
    if dim==2:
        for i in cluster:
            pos = cluster[i]
            if i=="noisy":
                for p in pos:
                    plt.plot(data[p,0],data[p,1],'o',c='k')
            else:
                for p in pos:
                    plt.plot(data[p,0],data[p,1],'o',c=color[i])            
    ##三维图
    elif dim==3:
        ax = plt.subplot(111,projection ='3d')
        for i in cluster:
            pos = cluster[i]
            if i=="noisy":
                for p in pos:
                    ax.scatter(data[p,0],data[p,1],data[p,2],c='black')
            else:
                for p in pos:
                    ax.scatter(data[p,0],data[p,1],data[p,2],c=color[i])
        
    plt.show()
        
        

data = np.array(genDataset(80,2))
cl = getCluster(data,3,3)
Show(data,cl)
结果展示

注意:
因为数据都是随机生成 并非聚类测试数据 所以结果不是特别好看 仅为模拟算法测试

下图参数:
二维空间80个点
eps=3 minPts=3
每种颜色代表一个集合 黑色代表局外点噪音
在这里插入图片描述


下图参数:
三维空间80个点
eps=6 minPts=4
每种颜色代表一个集合 黑色代表局外点噪音
在这里插入图片描述

  • 9
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
### 回答1: DBSCAN是一种聚类算法,用于发现具有高密度的区域,可以帮助识别数据中的离群值。Python中有许多用于实现DBSCAN算法的开源库,如scikit-learn、hdbscan、dbscan等。scikit-learn是最流行的用于机器学习数据挖掘的Python库之一,它包含了一个名为`sklearn.cluster.DBSCAN`的模块,可以用于实现DBSCAN算法。要使用这个模块,需要先将数据转换成numpy数组或pandas DataFrame格式,然后调用`DBSCAN()`函数并传入一些参数,如epsilon和min_samples,来指定算法的超参数。最后,调用`fit()`函数拟合模型并得到聚类结果。 ### 回答2: DBSCAN(Density-Based Spatial Clustering of Applications with Noise)算法是一种用于密度聚类算法。它通过基于数据点之间的密度来识别具有高密度的样本,并将其归为一类,同时可以识别出低密度区域中的异常样本。 DBSCAN算法实现可以使用Python编程语言。在Python中,我们可以使用第三方库如scikit-learn来实现DBSCAN算法。 首先,需要导入相应的库: ``` from sklearn.cluster import DBSCAN import numpy as np import matplotlib.pyplot as plt ``` 接下来,我们需要准备数据集。假设我们有一个二维数据集,可以使用NumPy库来生成一些随机数据: ``` # 生成数据 np.random.seed(0) X = np.random.randn(100, 2) ``` 然后,我们可以创建一个DBSCAN对象,并设置一些参数: ``` # 创建DBSCAN对象 dbscan = DBSCAN(eps=0.3, min_samples=5) ``` 其中,eps表示邻域的半径,min_samples表示一个样本被认为是核心样本的最小邻域内的样本数量。 接下来,我们可以使用fit_predict()函数进行聚类: ``` # 进行聚类 labels = dbscan.fit_predict(X) ``` 最后,我们可以将聚类结果进行可视化展示: ``` # 绘制聚类结果 plt.scatter(X[:, 0], X[:, 1], c=labels) plt.show() ``` 以上就是使用Python实现DBSCAN算法的简要步骤。通过调整参数,可以对数据集进行不同的聚类结果。需要注意的是,对于大规模数据集,使用DBSCAN算法可能会有一些效率问题,可以考虑使用其他优化算法或者降低数据维度来加快计算速度。 ### 回答3: DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的聚类算法,用于发现具有相似密度的数据集中的聚类DBSCAN算法实现可以使用Python编程语言。在Python中,可以使用scikit-learn(sklearn)库中的DBSCAN类来实现DBSCAN算法。 首先,需要导入相关的库和数据集。可以使用numpy来处理数据,使用matplotlib来绘制数据聚类结果的可视化。 然后,需要创建一个DBSCAN对象,并设置算法所需的参数。DBSCAN算法的两个重要参数是eps和min_samples。eps表示两个样本被认为是相邻的距离阈值,min_samples表示一个样本的最小邻居数量。 接下来,需要将数据传递给DBSCAN对象,并执行聚类算法。可以使用fit方法来拟合数据,计算出聚类结果。 最后,可以使用matplotlib库来绘制数据聚类结果的可视化。可以根据聚类结果给不同的簇分配不同的颜色,并绘制出相应的散点图。 通过使用Python中的DBSCAN算法,可以完成对具有相似密度的数据集的聚类任务。这种算法可以很好地处理密度变化较大的数据,并且对异常点也有较好的鲁棒性。同时,Python提供了丰富的数据处理和可视化库,使得DBSCAN算法实现更加方便和灵活。
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值