cluster by fast search and find of density peaks


说实在的这篇文章一发出来就遭到很多同行的鄙视,具体可以见Science上的评论,作为小菜,我还是保持沉默,好好学习为好。今天终于挤出时间来写这篇文章,闲话少说,直接上干货吧。


 

聚类是根据距离来进行的,关于距离也可以用一篇很长的文章来叙述,但是这篇文章不是关注这个方面,我们只关注有了距离dij以后,怎么更好的进行聚类,首先说一下这篇文章的优点吧:

a) 简单,里边不包含任何高深的迭代、梯度、隐函数等高深的词汇,基本上是个工科学生就能看懂;

b) 效率高,因为没有上述的过程,所以处理起来较为简单;

c) 能用对多种复杂的数据;

d) 对类别比较多时不敏感,这一点是很多经典的方法比不了的(kmean)。

这是我发现的优点,既然优点这么多,我们来具体看一下怎么实现的吧:

1. 计算局部密度

用dij代表数据点i和j之间的距离,i点的密度计算公式为

 p_{i}= \sum X(d_{ij}-d_{c})

上式中,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

 

 

原创文章,转载请注明出处,谢谢!


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM