说实在的这篇文章一发出来就遭到很多同行的鄙视,具体可以见Science上的评论,作为小菜,我还是保持沉默,好好学习为好。今天终于挤出时间来写这篇文章,闲话少说,直接上干货吧。
聚类是根据距离来进行的,关于距离也可以用一篇很长的文章来叙述,但是这篇文章不是关注这个方面,我们只关注有了距离dij以后,怎么更好的进行聚类,首先说一下这篇文章的优点吧:
a) 简单,里边不包含任何高深的迭代、梯度、隐函数等高深的词汇,基本上是个工科学生就能看懂;
b) 效率高,因为没有上述的过程,所以处理起来较为简单;
c) 能用对多种复杂的数据;
d) 对类别比较多时不敏感,这一点是很多经典的方法比不了的(kmean)。
这是我发现的优点,既然优点这么多,我们来具体看一下怎么实现的吧:
1. 计算局部密度
用dij代表数据点i和j之间的距离,i点的密度计算公式为
上式中,X为一个符号函数,定义为:X(x)=1 如果x<0,否则X(x)=0。
关于dc的确定,文章指出,dc可以选择为平均每个点的邻居局部密度为数据总数的1-2%(具体做实验时还得调整,这可能不是特别让人满意)
代码如下:
1 function y=get_P(dis,dc,label) 2 [m,n]=size(dis); 3 y=zeros(m,1); 4 for i=1:m 5 y(i)=0; 6 for j=1:m 7 if(i~=j) 8 if label==0 9 if(dis(i,j)-dc<0) 10 y(i)=y(i)+1; 11 end 12 else
13 y(i)=y(i)+exp(-(dis(i,j)/dc)^2); 14 end 15 end 16 end 17 end
确定dc
1 function y=get_dc(dis,percentage,kernel) 2 max_dis=max(max(dis))/2; 3 [m,n]=size(dis); 4 i=0; 5 for i=0:max_dis/1000:max_dis 6 p=get_P(dis,i,kernel); 7 p_ave=sum(p)/m; 8 if(p_ave>m*percentage) 9 break; 10 end 11 end 12 y=i; 13
14
2. 计算局部密度比本身大且距离本身最小的点
这个主要用于聚类,往后就会看到,聚类算法采用的是一种依附的策略,采用递归方法得到自身的类别,现在先做个铺垫。
对于每一个点来说,只要有密度比他大的点,那么这个phi一定存在;那么对于局部密度最大的点如何计算呢:
想想作者还是蛮聪明的,这样计算的话直接把密度最大的点给识别出来了。
上matlab代码
1 function y=get_phi(dis,p) 2 [m,n]=size(dis); 3 y=zeros(m,2); 4 [p1,index]=sort(p); 5 for i=1:m-1
6 tmp_dis=dis(index(i),:); 7 tmp_dis(index(1:i))=max(max(dis)); 8 [a,b]=min(tmp_dis); 9 y(index(i),:)=[a,b]; 10 end 11 y(index(m),1)=max(dis(index(m),:)); 12 y(index(m),2)=index(m);
具体编写程序的时候还是有一些技巧的。
ok 有了pi和,就可以画出一个decision graph的东西,文章中给出的是A:
越靠近右上角的点越容易被认为是聚类中心点(广义上的),或者我们也可以计算
画出来的图是B
实际上,在做实验的过程中,我发现通过B这个图更容易看出聚类中心有几个。
上面找到了聚类中心,剩下的问题就是如何聚类了。
3. 聚类过程
上面我们得到了聚类中心,每个点的比其密度大的最近的点,我们利用这两个信息进行聚类:
举个例子:
这个例子中的聚类中心是1和10,对18这个点进行聚类。
a)首先初始化1和10的label,分别为label_1和label_2,其他的不是聚类中心的点都没有聚类的label
b) 比18密度大的最近的点是4,这时如果4是有label的,那么将4的label赋给18,聚类完成;显然此时18没有聚类,那么进入 c)
c)比4密度大的最近的点是1,而1是有label的,那么将18的label标识为label_1,完成。
实际操作中可能b)和c)要进行很多次循环才行,但是这个肯定是个线性的,并且递归的深度也不会太深,这样就完成了聚类过程。
代码:
1 function new_label=cluster_density(phi_index,r,cluster_num) 2
3 m=length(phi_index); 4 new_label=zeros(m,1); 5 [r1,index_r1]=sort(r,'descend'); 6
7 for i=1:cluster_num 8 new_label(index_r1(i))=i; 9 tt=index_r1(i); 10 end 11
12 for i=1:m 13 if (new_label(i)==0) 14 j=i; 15 while(new_label(j)==0) 16 j=phi_index(j); 17 end 18 new_label(i)=new_label(j); 19 end 20
21 end
算法到这里大体完成了,下面给出几个聚类结果的例子:
原始和决策图
结果
文章链接:
Alex Rodriguez and Alessandro Laio, Clustering by fast search and find of density peaks, Science 344, 1492(2014)
http://www.sciencemag.org/content/344/6191/1492.full
原创文章,转载请注明出处,谢谢!