密度聚类之DBSCAN

      聚类算法K-means能够处理一些聚类问题,但是其本身存在缺点:1.对噪声(奇异点)很敏感;2.易收敛于局部最优解;3.不能发现非球状簇。

       具体应用时,需要提前设置K值,且K值对运算过程和结果的影响很大;对于不规则聚类的处理效果很差,如下图所示:


      本文将提出另一种聚类算法,基于密度的聚类算法——DBSAN,它能够很好地解决上面实际应用中存在的问题。

一、  密度聚类、DBSCAN

1、密度聚类的核心思想:

    1)   簇群是数据空间中的密集区域,在低密度区域处隔开;

    2)  一个簇被定义为最大的密度连接点集;

    3)  能够找到任意形状的簇集。

2、基本概念

    1)  DBSCAN算法中有两个重要参数 :ε和MinPts,前者为密度定义时的邻域半径,后者是定义核心点时的阈值(也就是可以构成一个cluster的所需之最小的点数);

    2)  ε邻域:以p对象为中心,半径为ε的圆形或球形空间内所有对象的集合;p的ε邻域:


    3)  高密度:ε邻域内至少包括MinPts个对象;低密度:ε邻域内对象少于MinPts个。因此上图中,p的密度为高密度,q的为低密度。

    4)  三种类型的点:

       ①  核心点:高密度点,它是位于cluster内部的点,属于某特定簇的点;

       ②  边界点:低密度点,但其与核心点相邻,它位于一个或多个簇的边缘地带,其属于一个簇或另外一个簇,归属不明确;

       ③  噪声点:既非核心点又非边界点,数据集中的干扰数据,不属于任何一个簇。


    5)  (直接)密度可达:如果p是核心点,q在其ε邻域内,则称q为从p直接密度可达。下图中,q从p直接密度可达,但p非从q密度可达,即:密度可达是非对称的。


    6)  间接密度可达。上面讲的是直接密度可达,如果p从p2直接密度可达,p2从p1直接密度可达,p1从q直接密度可达,q→p1→p2→p形成一个链,那么成p为从q间接密度可达,且q不能从p(间接)密度可达。综上:密度可达具有传递性但不具有对称性。


二、  DBSCAN的算法实现

      下面我们将对DBSCAN算法进行具体的实现和应用,具体将从三面入手:

1、算法伪代码以及实现

      从上面的原理和概念可知,DBSCAN算法工作过程大体如下:

      1)根据ε和MinPts的值,先从样本集D中找到一个核心点p(高密度点),并建立新簇C(p点放入此簇C中)。

      2)然后以此核心点p为基础,查找出其直接密度可达的点,并将这些点放入点集N(包括其自身)。

      3)对点集N中的所有点进行遍历:将这些点放入簇C中,对每个点进行邻域分析——对于核心点q(高密度点),将其直接邻域可达(p点间接邻域可达)的点,纳入到点集N中;对于非核心点边界点或噪声q,此时因为它是p点可达的(直接或间接),因此它将变成C的边界点,非噪声。

      4)重复上述过程3直到完成簇C的构建。注意:上述归入到簇C的点均将设置为已被访问,因为这些点均是核心点或边界点,类型明确!

      5)对于样本集中未访问到的点(对于簇C而言是噪声点),重复上述1—4过程,直到所有点均被遍历/访问到。

     综上所述,DBSCAN算法的伪代码如下:

(1) 首先将样本集D中的所有对象标记为未访问状态
(2) for(样本集D中每个对象p) do
(3)     if (p已经归入某个簇或标记为已访问) then
(4)         continue
(5)     else
(6)         检查对象p的eps邻域eps(p)
(7)         if (eps(p)包含的对象数不小于MinPts) then
(8)             标记对象p为核心点,并标记其已被访问
(9)             建立新簇C,p点放入簇C中
(10)            将p的eps(p)内的点放入点集N中
(11)            for (点集N中未处理的点q)  do
(12)                将q点放入簇C中,标记q点为已处理(已归入某簇或已访问)
(13)                if (eps(q)包含的对象数不小于MinPts) then
(14)                    将q点标记为核心点
(15)                    将其邻域内的点加入点集N中
(16)                else
(17)                    将q点标记为边界点
(18)        else
(19)            将p点标记为边界点或噪声点

      我们仍以iris数据集为样本进行相关的应用,具体python代码如下:

def dist_calc(a,b): #计算ab两点的距离,ab必须为np.array 
    import math
    return math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)

def region_search(p,eps,X): #邻域搜索,返邻域内满足eps区域条件的点的个数
    num = 0 #记录邻域内点的个数,包括p自身
    ind = [] #记录邻域内点的索引
    for i,x in enumerate(X):
        if(dist_calc(p,x) <= eps): #邻域搜索
            num += 1 
            ind.append(i)
    return num,ind #返回邻域内点个数以及其索引值

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.cluster import DBSCAN

%matplotlib inline

iris = datasets.load_iris()
X = iris.data[:,2:4]    #样本集
flag = [0 for x in X]  #访问标志,0未访问,1已访问
C_tp = [-1 for x in X] #类型标志,-1未分类,012345分别代表类型索引
eps = 1 #定义邻域半径
pts = 6   #定义最少点数
C = -1    #定义簇个数,-1代表未分类

for i,x in enumerate(X):
    N = [] #对簇中对象的索引进行记录
    if flag[i] == 1: #已访问,
        continue
    else: #i点未被访问时
        n_i,index_i = region_search(x,eps,X) #查找i点邻域
        if( n_i >= pts): #高密度,从i点直接密度可达
            flag[i] = 1 #i点为核心点,标记其已被访问
            C += 1 #定义簇
            C_tp[i] = C #将i点放到簇C中,此时i点为核心点
            N.extend(index_i) #将核心点邻域内点的索引值进行记录,归属于簇C
            
            for j in N: #对邻域内的点进行遍历查找
                if flag[j] == 1: #已访问,防止重复遍历
                    continue
                else:
                    flag[j] = 1 #标记已访问
                C_tp[j] = C #将核心点邻域内的点放到簇C中,密度可达的点

                n_j,index_j = region_search(X[j],eps,X) #查找j点的邻域
                if( n_j >= pts): #高密度,j点为核心点,邻域内为从i点间接密度可达
                    N.extend(index_j) #将核心点邻域内点索引进行记录,以便后续将其归入C簇中
                else: #低密度,j点为边界点或噪声
                    continue
        else: #低密度,直接密度不可达,噪声或边界点,此时不做相关操作
            continue
# print(C)
color = ('red','blue','yellow','black')
colors = np.array(color)[C_tp]
plt.scatter(X[:,0],X[:,1],c=colors,marker='+',s=20)
plt.show()

2、Scikit-learn函数调用

      此处仍以iris数据集为样本进行相关的应用,具体代码如下:

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.cluster import DBSCAN
%matplotlib inline
iris = datasets.load_iris()
X = iris.data[:,2:4]
# print(X)
plt.scatter(X[:,0],X[:,1],c='green')
plt.show()

db_pred = DBSCAN(eps=1,min_samples=6).fit_predict(X)
color = ('red','blue','yellow','black')
colors = np.array(color)[db_pred]
plt.scatter(X[:,0],X[:,1],c=colors,marker='+',s=20)
plt.show()

3、官方例程参考

      官方例程参考如下网址:

http://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html#examples-using-sklearn-cluster-dbscan

三、  关于ε和MinPts的选取



       


猜你喜欢

转载自blog.csdn.net/qq_33143379/article/details/80935987
今日推荐