机器学习——聚类——密度聚类法——DBSCAN

理论部分

1.1 提出背景

与K-means算法基于距离聚类不同,DBSCAN算法是基于样本点密度进行聚类。基于距离的聚类方法只适用于凸型数据尤其是球状分布的数据,而难以处理非凸数据,而密度聚类法可以很好地解决这个问题,密度聚类法的基本思想是只要一个区域中的点的密度大过某个阀值,就把它加到与之相近的聚类中去。

1.2 常见算法

基于密度的聚类算法有很多,例如DBSCAN算法、OPTICS算法、DENCLUE算法、基于密度峰值的聚类方法等。本篇我们着重讲解DBSCAN。

1.3 DBSCAN算法
1.3.1 基本概念

X = [ x 1 , x 2 , ⋯   , x n ] X=[x^{1},x^{2},\cdots,x_{n}] X=[x1,x2,,xn]为样本集, ϵ \epsilon ϵ表示领域半径, M M M表示密度阈值,则有:

· ϵ \epsilon ϵ领域
N ϵ ( x ) = { y ∈ X ∣ d ( x , y ) < ϵ } N_{\epsilon}(x)=\{y\in X|d(x,y)<\epsilon\} Nϵ(x)={yXd(x,y)<ϵ}
即表示以 x x x为中心, ϵ \epsilon ϵ为半径的圆内样本点的集合(包括自身)。

· ρ ( x ) \rho(x) ρ(x)密度

ρ ( x ) = ∣ N ϵ ( x ) ∣ \rho(x)=|N_{\epsilon}(x)| ρ(x)=Nϵ(x)
x x x的密度定义为 x x x ϵ \epsilon ϵ领域内的样本点个数。

·核心点

x ∈ X x\in X xX,若 ρ ( x ) ≥ M \rho(x) \geq M ρ(x)M,则称 x x x X X X的核心点,记 X X X中所有核心点构成的集合为 X c X_{c} Xc,所有非核心点构成的集合为 X n c X_{nc} Xnc

PS:简单来说,核心点即为满足在 ϵ \epsilon ϵ领域内至少有密度阈值个样本点的点。

·边界点

x ∈ X n c x\in X_{nc} xXnc(即 x x x为非核心点),且 ∃ y ∈ X \exists y \in X yX,满足:
y ∈ N ϵ ( x ) ∩ X c y \in N_{\epsilon}(x)\cap X_{c} yNϵ(x)Xc
则称 x x x为边界点,令样本点中所有边界点构成的集合为 X b p X_{bp} Xbp

PS:边界点可以理解为指那些落入核心点 ϵ \epsilon ϵ领域内的但不是核心点的样本点。

·噪声点

若样本点 x x x同时有:
x ∈ X , x ∉ X c a n d x ∉ X b p x\in X,x\notin X_{c} and x \notin X_{bp} xX,x/Xcandx/Xbp
则称 x x x为噪声点。

PS:噪声点可以理解为既不是核心点也不是边界点的样本点。即若某个样本点在其 ϵ \epsilon ϵ领域内不具有至少密度阈值个样本点,同时该样本点也不落在任何核心点的 ϵ \epsilon ϵ领域内,则称该样本点为噪声点。

在这里插入图片描述
如上图,蓝色样本点即为核心点,黑色样本为边界点,白色样本为噪声点。

·密度直达

对于样本点 x , y x,y x,y,若有:
x ∈ N ϵ ∣ ( y ) x\in N_{\epsilon|(y)} xNϵ(y)
ρ y = ∣ N ϵ ∣ ( y ) ∣ ≥ M \rho_{y}=|N_{\epsilon|(y)}|\geq M ρy=Nϵ(y)M
则称 x x x是由 y y y关于参数 ( ϵ , M ) (\epsilon,M) (ϵ,M)密度直达。

PS: x x x是由 y y y密度直达的等效为以下说法: y y y是核心点且 x x x处在 y y y ϵ \epsilon ϵ领域内。

在这里插入图片描述

·密度可达

对于样本点 x , y x,y x,y,如果存在一系列样本点 p 1 , p 2 , ⋯   , p n ( p 1 = x , p n = y ) p_{1},p_{2},\cdots ,p_{n}(p_{1}=x,p_{n}=y) p1,p2,,pn(p1=x,pn=y),若 p i + 1 p_{i+1} pi+1能够由 p i p_{i} pi密度直达 ( i = 1 , 2 , 3 , ⋯   , n − 1 ) (i=1,2,3,\cdots ,n-1) (i=1,2,3,,n1),则称 y y y 可由 x x x密度可达。
在这里插入图片描述

·密度相连

如果存在一个样本点 z z z,使得 x x x y y y均可由 z z z密度可达,则称 x x x y y y是密度相连的。
在这里插入图片描述

1.3.2 算法流程

在这里插入图片描述
该算法流程可大致描述如下:首先确定所有的核心点从而构成核心点集合(并将这些核心点标注为已访问)。而后每次选取一个核心点,如果其密度直达范围中存在另一个核心点,则将该核心点和可到达的那个核心点以及两者的密度直达范围中的样本点全部归属为一类。否则,第一类完成,开始第二类聚类,以此类推

1.3.3 参数设置

ϵ \epsilon ϵ或者 M M M设置得非常小,则意味着没有点是核心样本,可能会导致所有点被标记为噪声
ϵ \epsilon ϵ或者 M M M设置得非常大,可能会导致所有点形成单个簇。

1.3.3 优点

1.不必提前设置聚类数。
2.对非凸型数据处理能力较强,可以对任意类内稠密,类间系数的样本集进行聚类。
3.对异常点敏感性较低,可以较为有效地排除异常点的干扰。
4.可优化性强,部分步骤可由数据结构中的相关算法进行优化。

1.3.4 缺点

1.需要设置 ϵ \epsilon ϵ M M M,而这往往是依靠人的直觉和经验的。
2.在大规模数据集上效率较低。

在这里插入图片描述
属于簇的点是实心,噪声点则显示为空心,核心样本点显示为较大的标记,而边界点则显示为较小的标记,上图即验证了 ϵ \epsilon ϵ M M M取值大小对结果的影响。

1.3.5 可视化结果展示

在这里插入图片描述
上图为DBSCAN算法对于非球形分布数据的聚类过程。

在这里插入图片描述
上图为DBSCAN聚类结果(左图)和K-means聚类结果(右图)的对比

不同的 ϵ \epsilon ϵ M M M设置也会导致不同的结果:

加粗样式

1.4 评估指标

这里仍然可以采用轮廓系数进行评估,关于轮廓系数的介绍可以见另一篇博客K均值聚类法介绍

代码部分

2.1 不使用sklearn实现
import matplotlib.pyplot as plt
import random
import numpy as np
import math
from sklearn import datasets
 
list_1 = []
list_2 = []
def loadDataSet(fileName, splitChar='\t'):
    dataSet = []
    with open(fileName) as fr:
        for line in fr.readlines():
            curline = line.strip().split(splitChar)
            fltline = list(map(float, curline))
            dataSet.append(fltline)
    return dataSet
 
# 计算两个点之间的欧式距离,参数为两个元组
def dist(t1, t2):
    dis = math.sqrt((np.power((t1[0]-t2[0]),2) + np.power((t1[1]-t2[1]),2)))
    # print("两点之间的距离为:"+str(dis))
    return dis
 
# DBSCAN算法,参数为数据集,Eps为指定半径参数,MinPts为制定邻域密度阈值
def dbscan(Data, Eps, MinPts):
    num = len(Data)  # 点的个数
    # print("点的个数:"+str(num))
    unvisited = [i for i in range(num)]  # 没有访问到的点的列表
    # print(unvisited)
    visited = []  # 已经访问的点的列表
    C = [-1 for i in range(num)]
    # C为输出结果,默认是一个长度为num的值全为-1的列表
    # 用k来标记不同的簇,k = -1表示噪声点
    k = -1
    # 如果还有没访问的点
    while len(unvisited) > 0:
        # 随机选择一个unvisited对象
        p = random.choice(unvisited)
        unvisited.remove(p)
        visited.append(p)
        # N为p的epsilon邻域中的对象的集合
        N = []
        for i in range(num):
            if (dist(Data[i], Data[p]) <= Eps):# and (i!=p):
                N.append(i)
        # 如果p的epsilon邻域中的对象数大于指定阈值,说明p是一个核心对象
        if len(N) >= MinPts:
            k = k+1
            # print(k)
            C[p] = k
            # 对于p的epsilon邻域中的每个对象pi
            for pi in N:
                if pi in unvisited:
                    unvisited.remove(pi)
                    visited.append(pi)
                    # 找到pi的邻域中的核心对象,将这些对象放入N中
                    # M是位于pi的邻域中的点的列表
                    M = []
                    for j in range(num):
                        if (dist(Data[j], Data[pi])<=Eps): #and (j!=pi):
                            M.append(j)
                    if len(M)>=MinPts:
                        for t in M:
                            if t not in N:
                                N.append(t)
                # 若pi不属于任何簇,C[pi] == -1说明C中第pi个值没有改动
                if C[pi] == -1:
                    C[pi] = k
        # 剩余点既不是核心点也不是边界点
        else:
            C[p] = -1
 
    return C
 
dataSet = loadDataSet(r'D:\Deeplearning\788points.txt', splitChar=',')
C = dbscan(dataSet, 2, 14)
print(C)
x = []
y = []
for data in dataSet:
    x.append(data[0])
    y.append(data[1])
plt.figure(figsize=(8, 6), dpi=80)
plt.scatter(x,y, c=C, marker='o')
plt.show()

结果如下:
在这里插入图片描述

2.2 使用sklearn实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
%matplotlib inline
X1, y1=datasets.make_circles(n_samples=5000, factor=.6,
                                      noise=.05)
X2, y2 = datasets.make_blobs(n_samples=1000, n_features=2, centers=[[1.2,1.2]], cluster_std=[[.1]],
               random_state=9)

X = np.concatenate((X1, X2))
plt.scatter(X[:, 0], X[:, 1], marker='o')
plt.show()
y_pred = DBSCAN(eps = 0.1, min_samples = 10).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()

结果如下:
在这里插入图片描述
未经允许,请勿转载

欢迎交流

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值