聚类算法
划分聚类
密度聚类
DBSCAN
经典的密度聚类DBSCAN
基本概念
-
ε \varepsilon ε邻域(eps邻域)
ε \varepsilon ε是一个距离阈值,对于样本集S中的任意 x i x_i xi样本,与其距离小于等于 ε \varepsilon ε阈值的其他样本的集合,叫做样本 x i x_i xi的 ε \varepsilon ε邻域
记为:
N ε ( x i ) N_\varepsilon(x_i) Nε(xi)= { x j ∣ d i s t ( x i , x j ) ≤ ε { x_j|dist(x_i,x_j)\le \varepsilon } xj∣dist(xi,xj)≤ε} -
核心对象(点)
若 N ε ( x i ) N_\varepsilon(x_i) Nε(xi)内样本点数大于等于 M i n P t s MinPts MinPts阈值,即
| N ε ( x i ) N_\varepsilon(x_i) Nε(xi)| ≥ M i n P t s \ge MinPts ≥MinPts
则 x i x_i xi称为核心点,否则称为边界点 -
密度直达
x j x_j xj在 N ε ( x i ) N_\varepsilon(x_i) Nε(xi),且 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 3 , . . . p n p_1,p_2,p_3,...p_n p1,p2,p3,...pn, p 1 = x i , p n = x j p_1=x_i,p_n=x_j p1=xi,pn=xj, p i + 1 p_{i+1} pi+1可由 p i p_i pi密度直达,则 x j x_j xj可有 x i x_i xi密度可达(传递性) -
密度相连
若存在一个核心点 o o o,使得 x i x_i xi和 x j x_j xj均由 o o o密度可达
则称 x i x_i xi和 x j x_j xj密度相连
i. 所有密度相连的点分为一簇,同一簇的点必定密度相连
ii. 一个核心对象所有密度可达的点集合,分为一簇
DBSCAN基本思想
算法流程
python实现
sklearn库的实现
DBSCAN优点及缺点
优点
- 适用凸、非凸的稠密数据集
不像KMeans/Birch之类的,只适用凸集 - 不需事先指定聚类簇数 k k k
- 聚类完成可以识别噪声点 ,对异常点不敏感
缺点
- 非稠密数据,距离差异大的样本集,都不适用DBSCAN
- 样本集大时,聚类收敛时间较长,使用kd_tree,ball_tree增加空间复杂度
- ε 和 M i n P t s \varepsilon 和MinPts ε和MinPts需联合调参,比较复杂,DBSCAN对这俩个参数比较敏感
ε 和 M i n P t s \varepsilon 和MinPts ε和MinPts选参
- 交叉验证
取 ε 和 M i n P t s \varepsilon 和MinPts ε和MinPts合理的数值组合,使DBSCAN聚类的评价指标最优,比如轮廓系数,DB指数等 - 网格搜索
- 手肘法,根据MinPts,确定 ε \varepsilon ε值
i. MinPts取初始值 k = n + 1 k=n+1 k=n+1,即特征数加 1 1 1
ii.迭代每个样本 x i x_i xi,计算与样本集S内其他样本的距离,取第 k k k近的距离 k d i s t k_{dist} kdist,如 [ 0 , 1 , 2 , 2 , 3 , 4 , 5 ] [0,1,2,2,3,4,5] [0,1,2,2,3,4,5]中第三近的距离为3,0表示样本与自己的距离。将所有样本的 k d i s t k_{dist} kdist放入列表 L L L
iii. 对 L L L从大到小排序,作线性可视化,取拐点处的 k d i s t k_{dist} kdist作为 ε \varepsilon ε值
python 代码手肘法实现:
"""
decide 'eps' according to 'MinPts'
'MinPts'=n+1
"""
import numpy as np
from matplotlib import pyplot as plt
from sklearn.preprocessing import StandardScaler
class SelectEPS(object):
def __init__(self,datapath):
self.x=np.loadtxt(datapath)
self.x_scale=StandardScaler().fit_transform(self.x)
self.m,self.n=x.shape
def select_eps(self):
#初始化MinPts
min_pts=self.n+1
k_dist_list=[]
#遍历样本点
for i in range(self.m):
p=self.x[i]
p_to_other=self.l2(p)
print("Current sample:",p)
print("Distance of p with others:",p_to_other)
k_dist_list.append(self.get_k_th_dist(min_pts,p_to_other))
print(k_dist_list)
k_dist_list_sort=np.sort(k_dist_list)[::-1]
plt.scatter(range(self.m),k_dist_list_sort,marker="o")
plt.xlabel("index")
plt.ylabel("k_dist ",rotation="horizontal")
plt.title("k_dist of all samples")
plt.show()
def l2(self,x):
"""
计算单个样本与样本集S内其他样本的距离
x:single sample,1dim
return:distance,1dim
"""
return np.sqrt(np.sum((x-self.x)**2,axis=1))
def get_k_th_dist(self,k,dist_list):
"""
从包含0的几个距离中取最近的k个
"""
#排序
sort_dist=np.sort(dist_list)
#取出第k近的值
i=0
while i<k:
if sort_dist[i]==0:
k+=1
i+=1
if i>len(sort_dist)-1:
return "no result"
continue
elif sort_dist[i]==sort_dist[i-1]:
k+=1
i+=1
if i>len(sort_dist)-1:
return "no result"
continue
else:
i+=1
if i>len(sort_dist)-1:
return "no result"
#取到除0外的第k个最近距离
return sort_dist[i-1]
if __name__=="__main__":
eps=SelectEPS("data.txt")
eps.select_eps()
# d=eps.get_k_th_dist(1,[0,0,0,0,0,1,1,1,2,2,2,3,4,4])
# print(d)
OPTICS聚类
Ordering Points To Identify Cluster Structure
- DBSCAN算法的衍生算法
- 引入可达距离,解决 ε \varepsilon ε参数确定的问题
定义
- 样本点 x i x_i xi的核心距离
若样本点 x i x_i xi为核心点,则其有核心距离,否则没有核心距离
如下图,在指定 ε \varepsilon ε距离阈值和MinPts=4时,
样本点 x i x_i xi第一近邻点为本身(这里计入本身点),第二近邻点为样本2,第三近邻点为样本3 ( x 1 ) (x_1) (x1),第四(MinPts)近邻点为样本4,也就是说第MinPts近邻点在样本点 x i x_i xi的 ε \varepsilon ε邻域内,则样本点 x i x_i xi必为核心点,且其核心距离为样本点 x i x_i xi到第MinPts近邻点之间的距离,如图中 c ( x i ) c(x_i) c(xi)
- 样本点 x j x_j xj到样本点 x i x_i xi的可达距离
只有样本点 x i x_i xi为核心点时才被可达,否则这个可达距离不存在
如上图样本点 x i x_i xi为核心点,则其 ε \varepsilon ε邻域内的点 x j x_j xj到 x i x_i xi的可达距离为:
m a x ( d i j , c ( x i ) ) max(d_{ij},c(x_i)) max(dij,c(xi))
d i j d_{ij} dij为 x i x_i xi, x j x_j xj之间的距离
c ( x i ) c(x_i) c(xi)为核心点 x i x_i xi的核心距离
显然有
x 1 x_1 x1到 x i x_i xi的可达距离 r ( x 1 ) = c ( x i ) r(x_1)=c(x_i) r(x1)=c(xi)
x 2 x_2 x2到 x i x_i xi的可达距离 r ( x 2 ) = d i 2 r(x_2)=d_{i2} r(x2)=di2
OPTICS算法流程
- 对于样本集S, m 个 样 本 , n 个 特 征 m个样本,n个特征 m个样本,n个特征:
初始化所有点的可达距离为inf, r e a c h _ d i s t = a r r a y ( [ n p . i n f ] ∗ m ) reach\_dist=array([np.inf]*m) reach_dist=array([np.inf]∗m)
初始化根据可达距离从小到大排序的样本的列表全为0, o r d e r i n g = n p . z e r o s ( m , d t y p e = i n t ) ordering=np.zeros(m,dtype=int) ordering=np.zeros(m,dtype=int)
初始化样本是否已处理的标记全为False, p r o c e s s e d = n p . z e r o s ( m , d t y p e = b o o l ) processed=np.zeros(m,dtype=bool) processed=np.zeros(m,dtype=bool) - 假设 ε \varepsilon ε为inf,根据参数MinPts计算出所有点核心距离,记core_dist,核心距离大于 ε \varepsilon ε阈值,则不存在核心距离用inf 表示
- 从未处理的点中取当前可达距离最小的点 i d x = n p . a r g m i n ( r e a c h _ d i s t ) idx=np.argmin(reach\_dist) idx=np.argmin(reach_dist),放入 o r d e r i n g ordering ordering第一个位置,并标记是否处理为True, p r o c e s s e d [ i d x ] = T r u e processed[idx]=True processed[idx]=True,若当前 i d x idx idx样本具有核心距离,计算当前点 i d x idx idx与 p r o c e s s e d processed processed中为False的点之间的可达距离 r d i s t rdist rdist,若 r d i s t rdist rdist中的可达距离小于 r e a c h _ d i s t reach\_dist reach_dist中对应的可达距离值,则更新替换为 r d i s t rdist rdist中的值;若当前 i d x idx idx不具有核心距离(inf),即不是核心点,则不处理
- 重复3,取当前未处理的样本,即 p r o c e s s e d = F a l s e processed=False processed=False的样本,返回这些未处理的样本在 r e a c h _ d i s t reach\_dist reach_dist中可达距离最小的一个样本点 i d x idx idx,加入 o r d e r i n g ordering ordering的第二个位置,并标记是否处理为True, p r o c e s s e d [ i d x ] = T r u e processed[idx]=True processed[idx]=True. 是核心点则计算它与其他未处理的点的可达距离,否则不处理,直到所有的样本处理完,算法结束。
演示示例
有如下数据
x = [ 1 3 3 3 2 0.2 10 0.8 10.8 1.4 12 0.8 ] \begin{gathered} x=\begin{bmatrix} 1 & 3 \\ 3 & 3 \\ 2 & 0.2 \\ 10 &0.8 \\ 10.8&1.4\\ 12&0.8\end{bmatrix} \quad \end{gathered} x=⎣⎢⎢⎢⎢⎢⎢⎡1321010.812330.20.81.40.8⎦⎥⎥⎥⎥⎥⎥⎤
Python实现OPTICS
百度网盘:https://pan.baidu.com/s/1UUgK-uPfWpRopJ_C1FZY9w
提取码:i4tn
Sklearn库实现OPTICS
import numpy as np
from sklearn.cluster import OPTICS
from matplotlib import pyplot as plt
#load data
x=np.loadtxt("optics_sample.txt")
#instantiate
optics=OPTICS(max_eps=np.inf,eps=3,min_samples=3,cluster_method="dbscan")
optics.fit(x)
#按照可达距离从小到大排序的样本点
optics.ordering_
#[0,1,2,3,4,5]
#样本的可达距离
rdist=optics.reachability_[optics.ordering_]
#可视化可达距离
plt.plot(range(x.shape[0]),rdist,marker="o",markeredgewidth=3,linestyle="-")
plt.title("sklearn-optics")
plt.grid()
plt.xlabel("index")
plt.ylabel("reach dist")
plt.show()
排序样本的可达距离,每一个低谷为一个聚类簇
可视化聚类样本点:
y_pred=optics.labels_
plt.scatter(x[:,0],x[:,1],s=50,c=y_pred,marker="^",edgecolors=None,linewidths=1,cmap="cool")
plt.title("cluster samples")
plt.grid()
plt.xlabel("f1")
plt.ylabel("f2")
plt.axis("equal")
plt.show()