說實在的這篇文章一發出來就遭到很多同行的鄙視,具體可以見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
原創文章,轉載請注明出處,謝謝!