机器学习笔记(十一)聚类算法OPTICS原理和实践

OPTICS聚类算法是基于密度的聚类算法,全称是Ordering points to identify the clustering structure。提到基于密度的聚类算法,应该很快会想到前面介绍的DBSCAN聚类算法,事实上,OPTICS也是为了优化DBSCAN而出现的。

一、原理

在DBSCAN算法中,有两个比较重要的参数:邻域半径eps和核心对象的最小邻域样本数min_samples,选择不同的参数会导致最终聚类的结果千差万别,而在高维数据中,两个参数的联合调参也不是一件容易的事。OPTICS算法的提出就是为了帮助DBSCAN算法选择合适的参数,降低输入参数的敏感度。实际上,OPTICS并不显式的生成数据聚类结果,只是对数据集中的对象进行排序,得到一个有序的对象列表,通过该有序列表,可以得到一个决策图,通过决策图可以选择不同的eps参数进行DBSCAN聚类。在继续阅读下面的内容之前,需要先了解DBSCAN的相关内容,因为本文的部分概念来自于DBSCAN。

在DBSCAN的基础上,OPTICS定义了两个新的距离概念:

(1)核心距离

对于一个给定的核心对象X,使得X成为核心对象的最小邻域距离 r 就是X的核心距离。这句话乍一看有点绕,其实仔细读两遍就明白了,假如在DBSCAN中我们定义 eps = 1.2 和  min_samples=5,X在eps = 1.2的邻域内有8个样本点,则X是核心对象,但是我们发现距离X最近的第5个点和X的距离是0.8,那么核心对象 X 的核心距离就是 0.8,显然每个核心对象的核心距离并不都是相同的。参考图1,注意在计算 min_samples 的时候,一般也包括样本点自身,所以只需在P点eps邻域内找到7个点,那么P点就是核心点。

(2)可达距离

如果X是核心对象,则对象 Y 到对象 X 的可达距离就是Y到X的欧氏距离和X的核心距离的最大值,如果X不是核心对象,则Y和X之间的可达距离就没有意义(不存在可达距离),显然,数据集中有多少核心对象,那么 Y 就有多少个可达距离。在下文介绍 API 的时候,我们会介绍在OPTICS中,一般默认设置 eps 为无穷大,即只要数据集的样本数不少于 min_samples,那么任意一个样本点都是核心对象,即都有核心距离,且任意两个对象之间都存在可达距离。

图1

1.1 算法描述

OPTICS的原理并不复杂,只不过大多数介绍资料都喜欢列举一些广义的算法流程或者伪代码,虽然满足算法介绍的严谨性,但是阅读起来不免显得晦涩难懂,没有阅读的欲望。因此,和之前的文章一样,本文也是先介绍OPTICS的标准算法流程,然后再以案例的形式介绍流程的具体执行逻辑,如果算法流程不能一下子理解的话,可以先跳过直接看后面的案例,然后再回来看标准流程。

OPTICS算法流程:

  1. 已知数据集 D,创建两个队列,有序队列O和结果队列R(有序队列用来存储核心对象及其该核心对象的密度直达对象,并按可达距离升序排列;结果队列用来存储样本点的输出次序。可以把有序队列里面放的理解为待处理的数据,而结果队列里放的是已经处理完的数据)。
  2. 如果D中所有点都处理完毕或者不存在核心点,则算法结束。否则,选择一个未处理(即不在结果队列R中)且为核心对象的样本点 p,首先将 p 放入结果队列R中,并从D中删除 p。然后找到 D 中 p 的所有密度直达样本点 x,计算 x 到 p 的可达距离,如果 x 不在有序队列 O 中,则将 x 以及可达距离放入 O 中,若 x 在 O 中,则如果 x 新的可达距离更小,则更新 x 的可达距离,最后对 O 中数据按可达距离从小到大重新排序。
  3. 如果有序队列 O 为空,则回到步骤2,否则取出 O 中第一个样本点 y(即可达距离最小的样本点),放入 R 中,并从 D 和 O 中删除 y。如果 y 不是核心对象,则重复步骤 3(即找 O 中剩余数据可达距离最小的样本点);如果 y 是核心对象,则找到 y 在 D 中的所有密度直达样本点,并计算到 y 的可达距离,然后按照步骤2将所有 y 的密度直达样本点更新到 O 中。
  4. 重复步骤2、3,直到算法结束。最终可以得到一个有序的输出结果,以及相应的可达距离。

已知样本数据集为:D = {[1, 2], [2, 5],  [8, 7], [3, 6],  [8, 8], [7, 3], [4,5]},为了更好地标识索引,我们以表格标识数据如下:

图2
表1
索引0123456核心对象
元素(1, 2)(2, 5)(8, 7)(3, 6)(8, 8)(7, 3)(4, 5) 
核心距离3.161.411.01.411.03.611.41 
第一次可达距离inf3.168.604.479.216.084.240
第二次可达距离----6.321.416.705.382.01
第三次可达距离----5.09--5.395.01.413
第四次可达距离----4.47--5.03.61--6
第五次可达距离----4.12--

5.0

(5.10)

----5
第六次可达距离--------1.0----2
输出顺序0152643 
可达距离inf3.164.121.411.03.611.41 

假设eps = inf,min_samples=2,则数据集D在OPTICS算法上的执行步骤如下:

  1. 计算所有的核心对象和核心距离,因为 eps 为无穷大,则显然每个样本点都是核心对象。因为 min_samples=2,则每个核心对象的核心距离就是离自己最近样本点到自己的距离(样本点自身也是邻域元素之一),具体如上表所示。
  2. 随机在 D 中选择一个核心对象,假设选择 0 号元素,将 0 号元素放入 R 中,并从 D 中删除。因为 eps = inf,则其他所有样本点都是 0 号元素的密度直达对象,计算其他所有元素到 0 号元素的可达距离(实际就是计算所有元素到 0 号元素的欧氏距离,如表1第一次可达距离),并按可达距离排序,添加到序列 O 中。
  3. 此时 O 中可达距离最小的元素是 1 号元素,取出 1 号元素放入 R ,并从 D 和 O 中删除,因为 1 号元素是核心对象,找到 1 号元素在 D 中的所有密度直达对象(剩余的所有样本点),并计算可达距离,同时更新 O(如表1第二次可达距离)。
  4. 此时 O 中可达距离最小的元素是 3 号元素,取出 3 号元素放入 R ,并从 D 和 O 中删除,因为 3 号元素是核心对象,找到 3 号元素在 D 中的所有密度直达对象(剩余的所有样本点),并计算可达距离,同时更新 O(如表1第三次可达距离)。
  5. 此时 O 中可达距离最小的元素是 6 号元素,取出 6 号元素放入 R ,并从 D 和 O 中删除,因为 6 号元素是核心对象,找到 6 号元素在 D 中的所有密度直达对象(剩余的所有样本点),并计算可达距离,同时更新 O(如表1第四次可达距离)。
  6. 此时 O 中可达距离最小的元素是 5 号元素,取出 5 号元素放入 R ,并从 D 和 O 中删除,因为 5 号元素是核心对象,找到 5 号元素在 D 中的所有密度直达对象(剩余的所有样本点),并计算可达距离,同时更新 O(如表1第五次可达距离)。注意本次计算的4号元素到5号元素的可达距离是5.10,大于5.0,因此不更新4号元素的可达距离。
  7. 此时 O 中可达距离最小的元素是 2 号元素,取出 2 号元素放入 R ,并从 D 和 O 中删除,因为 2 号元素是核心对象,找到 2 号元素在 D 中的所有密度直达对象(剩余的所有样本点),并计算可达距离,同时更新 O(如表1第六次可达距离)。
  8. 此时 O 中可达距离最小的元素是 4 号元素,取出 4 号元素放入 R ,并从 D 和 O 中删除,因为 D 已空,O 也已空,程序结束。根据表1,最终的结果序列 R 的元素索引输出顺序为:0、1、3、6、5、2、4,可达距离如表1最后一行所示。

我们按照最终的输出顺序绘制可达距离图(注意,因为第一个元素没有可达距离,或者说可达距离是无穷大,故图中没有标出 0 号元素的可达距离):

图3

可以发现,可达距离呈现两个波谷,也即表现为两个簇,波谷越深,表示簇越紧密,只需要在两个波谷之间取一个合适的 eps 分隔值(图中蓝色的直线,例如两个可达距离的平均值),使用 DBSCAN 算法就会聚类为两个簇。即第一个簇的元素为:0、1、3、6、5;第二个簇的元素为:2、4。下面我们通过sklearn库来验证我们的结果。

二、实践

sklearn库同样为我们封装了 OPTICS 算法的API,供我们直接使用。

2.1 验证

基于1.1的数据集,使用OPTICS验证算法结果如下:

from sklearn.cluster import OPTICS
import numpy as np

X = np.array([[1, 2], [2, 5],  [8, 7],[3, 6],  [8, 8], [7, 3], [4,5]])

clustering = OPTICS(min_samples=2).fit(X)


print(clustering.core_distances_)
'''
array([3.16227766, 1.41421356, 1.  , 1.41421356, 1.  ,3.60555128, 1.41421356])
'''

print(clustering.ordering_)
'''
array([0, 1, 3, 6, 5, 2, 4])
'''

print(clustering.reachability_)
'''
array([inf, 3.16227766, 4.12310563, 1.41421356, 1.        ,3.60555128, 1.41421356])
'''

print(clustering.labels_)
'''
array([0, 0, 1, 0, 1, 0, 0])
'''

根据图3,选择 eps=3.8,使用DBSCAN算法验证如下:

import sklearn

db = sklearn.cluster.DBSCAN(eps=3.8,min_samples=2).fit(X)
db.labels_

## array([0, 0, 1, 0, 1, 0, 0])

参考资料

[1] https://blog.csdn.net/PRINCE2327/article/details/110412944

 

  • 22
    点赞
  • 92
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值