题记:没有落脚到数据结构的对算法的理解都是没有灵魂的复制粘贴!
其实很多算法,我们通过开源的算法包比如sklearn,tensorflow等,实现都很简单,几行代码,调调参数就出来了,一般也不会出现什么大问题。但是我觉得实际得算法他应该跟诗歌一样,每个人对它得理解和未来得改动应该是都有些微得差别得,而这些微得差别正推动者科研得进步。这就需要从原理和实现上深入得了解和直观感受。而掉包,是缺少这一丝灵气的。
DBSCAN密度聚类算法
西瓜书上对于密度聚类的讲解:
聚类的过程示例:
直观理解:
可以这样理解DBSCAN:
1、在空间上如果在小于eps的距离上存在大于或者等于MinPts个个体,那么这几个个体就可以看作一个小的团伙,刚开始有M个团伙。
2、这个团伙内的每个成员都可以将手伸出到eps距离外。外面的人只要被拉到就变成了这个团伙的人。
3、直到刚开始的M个团伙都被拉完了,算法也就停止了。
分析
1、算法主要过程是距离的计算,并就近样本的选取
2、在每个“团体”向外伸张的过程明显是个深度优先或者广度优先遍历问题。
3、所以可以用队列来存储这个节点进行广度优先遍历。
算法python实现
代码很短,基本逻辑都在了。
import numpy as np
import pandas as pd
import collections
matrix_data = np.asarray(pd.read_csv("../../state/rawData/CompleteOrder.csv", header=None))
from core.cluster.caculationDistance import euclideanDistance
allDistance=euclideanDistance(matrix_data,matrix_data)
eps=110
minPts=3
allCluster=[]
#直接可达矩阵
matrixDirect=allDistance<eps
#每个样本点的pts
directDensity=matrixDirect.sum(axis=1)-1#减去1的作用是去掉自己
#核心对象集
cluster=[i for i,v in enumerate(directDensity) if v>minPts]
while cluster:#通过密度可达一直到核心集为空
"""
这里求取样本之间的直接可达用的是笨方法,直接计算出所有的然后去筛选,
可以想想这种方法的时间复杂度是很大的。为改进依据距离找点效率比较低
的现状,需要用到的改进算法:
1、kd_tree
2、ball_tree
3、brute
特点:
1、对于两个参数的设置非常的敏感
2、当数据分布及其不均匀时不好用
在量级相差较大的数据集上不适合应用该方法进行聚类。刚好印证了我研究该数据集的问题
"""
randCluster=cluster[np.random.randint(len(cluster))]
#广度优先遍历
beVisited={}
myQue=collections.deque()
myQue.append(randCluster)
while myQue:
bePop=myQue.popleft()
if not beVisited.get(bePop,False):#没有访问过
beVisited[bePop]=True
for i,v in enumerate(matrixDirect[bePop]):
if v and not beVisited.get(i,False):
myQue.append(i)
else:
pass
thisCluster=beVisited.keys()
allCluster.append(thisCluster)
cluster=list(set(cluster).difference(thisCluster))
print("聚类结果")
print(allCluster)
改进
很明显为我在求取距离的过程中采取暴力运算的方法,效率比较低,改进依据距离找点效率比较低的现状,需要用到的改进算法:
1、kd_tree
2、ball_tree
3、brute
用sklearn工具包求取的过程中可以通过algrathom这个参数进行设置。
后记
有些问题(比如我遇到的)通过密度聚类不管怎样调参,死活都聚类不出来。主要原因是数据分布的太不均匀(可以理解为非常不均匀的荷塘中间有几个小溪连着),比如不均匀到样本间量级相差都很大的情况,这种时候就不适合用密度聚类,可以自己找数据验证下。