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