發表在 Science 上的一種新聚類算法

 今年 6 月份,Alex Rodriguez 和 Alessandro Laio 在 Science 上發表了一篇名爲《Clustering by fast search and find of density peaks》的文章,爲聚類算法的設計提供了一種新的思路。雖然文章出來後遭到了衆多讀者的質疑,但整體而言,新聚類算法的基本思想很新穎,且簡單明快,值得學習。這個新聚類算法的核心思想在於對聚類中心的刻畫上,本文將對該算法的原理進行詳細介紹,並對其中的若干細節展開討論

最後,附上作者在補充材料裏提供的 Matlab 示例程序 (加了適當的代碼註釋)。

  1. clear all  
  2. close all  
  3. disp('The only input needed is a distance matrix file')  
  4. disp('The format of this file should be: ')  
  5. disp('Column 1: id of element i')  
  6. disp('Column 2: id of element j')  
  7. disp('Column 3: dist(i,j)')  
  8.   
  9. %% 從文件中讀取數據  
  10. mdist=input('name of the distance matrix file (with single quotes)?\n');  
  11. disp('Reading input distance matrix')  
  12. xx=load(mdist);  
  13. ND=max(xx(:,2));  
  14. NL=max(xx(:,1));  
  15. if (NL>ND)  
  16.   ND=NL;  %% 確保 DN 取爲第一二列最大值中的較大者,並將其作爲數據點總數  
  17. end  
  18.   
  19. N=size(xx,1); %% xx 第一個維度的長度,相當於文件的行數(即距離的總個數)  
  20.   
  21. %% 初始化爲零  
  22. for i=1:ND  
  23.   for j=1:ND  
  24.     dist(i,j)=0;  
  25.   end  
  26. end  
  27.   
  28. %% 利用 xx 爲 dist 數組賦值,注意輸入只存了 0.5*DN(DN-1) 個值,這裏將其補成了滿矩陣  
  29. %% 這裏不考慮對角線元素  
  30. for i=1:N  
  31.   ii=xx(i,1);  
  32.   jj=xx(i,2);  
  33.   dist(ii,jj)=xx(i,3);  
  34.   dist(jj,ii)=xx(i,3);  
  35. end  
  36.   
  37. %% 確定 dc  
  38.   
  39. percent=2.0;  
  40. fprintf('average percentage of neighbours (hard coded): %5.6f\n', percent);  
  41.   
  42. position=round(N*percent/100); %% round 是一個四捨五入函數  
  43. sda=sort(xx(:,3)); %% 對所有距離值作升序排列  
  44. dc=sda(position);  
  45.   
  46. %% 計算局部密度 rho (利用 Gaussian 核)  
  47.   
  48. fprintf('Computing Rho with gaussian kernel of radius: %12.6f\n', dc);  
  49.   
  50. %% 將每個數據點的 rho 值初始化爲零  
  51. for i=1:ND  
  52.   rho(i)=0.;  
  53. end  
  54.   
  55. % Gaussian kernel  
  56. for i=1:ND-1  
  57.   for j=i+1:ND  
  58.      rho(i)=rho(i)+exp(-(dist(i,j)/dc)*(dist(i,j)/dc));  
  59.      rho(j)=rho(j)+exp(-(dist(i,j)/dc)*(dist(i,j)/dc));  
  60.   end  
  61. end  
  62.   
  63. % "Cut off" kernel  
  64. %for i=1:ND-1  
  65. %  for j=i+1:ND  
  66. %    if (dist(i,j)<dc)  
  67. %       rho(i)=rho(i)+1.;  
  68. %       rho(j)=rho(j)+1.;  
  69. %    end  
  70. %  end  
  71. %end  
  72.   
  73. %% 先求矩陣列最大值,再求最大值,最後得到所有距離值中的最大值  
  74. maxd=max(max(dist));   
  75.   
  76. %% 將 rho 按降序排列,ordrho 保持序  
  77. [rho_sorted,ordrho]=sort(rho,'descend');  
  78.    
  79. %% 處理 rho 值最大的數據點  
  80. delta(ordrho(1))=-1.;  
  81. nneigh(ordrho(1))=0;  
  82.   
  83. %% 生成 delta 和 nneigh 數組  
  84. for ii=2:ND  
  85.    delta(ordrho(ii))=maxd;  
  86.    for jj=1:ii-1  
  87.      if(dist(ordrho(ii),ordrho(jj))<delta(ordrho(ii)))  
  88.         delta(ordrho(ii))=dist(ordrho(ii),ordrho(jj));  
  89.         nneigh(ordrho(ii))=ordrho(jj);   
  90.         %% 記錄 rho 值更大的數據點中與 ordrho(ii) 距離最近的點的編號 ordrho(jj)  
  91.      end  
  92.    end  
  93. end  
  94.   
  95. %% 生成 rho 值最大數據點的 delta 值  
  96. delta(ordrho(1))=max(delta(:));  
  97.   
  98. %% 決策圖  
  99.   
  100. disp('Generated file:DECISION GRAPH')   
  101. disp('column 1:Density')  
  102. disp('column 2:Delta')  
  103.   
  104. fid = fopen('DECISION_GRAPH', 'w');  
  105. for i=1:ND  
  106.    fprintf(fid, '%6.2f %6.2f\n', rho(i),delta(i));  
  107. end  
  108.   
  109. %% 選擇一個圍住類中心的矩形  
  110. disp('Select a rectangle enclosing cluster centers')  
  111.   
  112. %% 每臺計算機,句柄的根對象只有一個,就是屏幕,它的句柄總是 0  
  113. %% >> scrsz = get(0,'ScreenSize')  
  114. %% scrsz =  
  115. %%            1           1        1280         800  
  116. %% 1280 和 800 就是你設置的計算機的分辨率,scrsz(4) 就是 800,scrsz(3) 就是 1280  
  117. scrsz = get(0,'ScreenSize');  
  118.   
  119. %% 人爲指定一個位置,感覺就沒有那麼 auto 了 :-)  
  120. figure('Position',[6 72 scrsz(3)/4. scrsz(4)/1.3]);  
  121.   
  122. %% ind 和 gamma 在後面並沒有用到  
  123. for i=1:ND  
  124.   ind(i)=i;   
  125.   gamma(i)=rho(i)*delta(i);  
  126. end  
  127.   
  128. %% 利用 rho 和 delta 畫出一個所謂的“決策圖”  
  129.   
  130. subplot(2,1,1)  
  131. tt=plot(rho(:),delta(:),'o','MarkerSize',5,'MarkerFaceColor','k','MarkerEdgeColor','k');  
  132. title ('Decision Graph','FontSize',15.0)  
  133. xlabel ('\rho')  
  134. ylabel ('\delta')  
  135.   
  136. subplot(2,1,1)  
  137. rect = getrect(1);   
  138. %% getrect 從圖中用鼠標截取一個矩形區域, rect 中存放的是  
  139. %% 矩形左下角的座標 (x,y) 以及所截矩形的寬度和高度  
  140. rhomin=rect(1);  
  141. deltamin=rect(2); %% 作者承認這是個 error,已由 4 改爲 2 了!  
  142.   
  143. %% 初始化 cluster 個數  
  144. NCLUST=0;  
  145.   
  146. %% cl 爲歸屬標誌數組,cl(i)=j 表示第 i 號數據點歸屬於第 j 個 cluster  
  147. %% 先統一將 cl 初始化爲 -1  
  148. for i=1:ND  
  149.   cl(i)=-1;  
  150. end  
  151.   
  152. %% 在矩形區域內統計數據點(即聚類中心)的個數  
  153. for i=1:ND  
  154.   if ( (rho(i)>rhomin) && (delta(i)>deltamin))  
  155.      NCLUST=NCLUST+1;  
  156.      cl(i)=NCLUST; %% 第 i 號數據點屬於第 NCLUST 個 cluster  
  157.      icl(NCLUST)=i;%% 逆映射,第 NCLUST 個 cluster 的中心爲第 i 號數據點  
  158.   end  
  159. end  
  160.   
  161. fprintf('NUMBER OF CLUSTERS: %i \n', NCLUST);  
  162.   
  163. disp('Performing assignation')  
  164.   
  165. %% 將其他數據點歸類 (assignation)  
  166. for i=1:ND  
  167.   if (cl(ordrho(i))==-1)  
  168.     cl(ordrho(i))=cl(nneigh(ordrho(i)));  
  169.   end  
  170. end  
  171. %% 由於是按照 rho 值從大到小的順序遍歷,循環結束後, cl 應該都變成正的值了.   
  172.   
  173. %% 處理光暈點,halo這段代碼應該移到 if (NCLUST>1) 內去比較好吧  
  174. for i=1:ND  
  175.   halo(i)=cl(i);  
  176. end  
  177.   
  178. if (NCLUST>1)  
  179.   
  180.   % 初始化數組 bord_rho 爲 0,每個 cluster 定義一個 bord_rho 值  
  181.   for i=1:NCLUST  
  182.     bord_rho(i)=0.;  
  183.   end  
  184.   
  185.   % 獲取每一個 cluster 中平均密度的一個界 bord_rho  
  186.   for i=1:ND-1  
  187.     for j=i+1:ND  
  188.       %% 距離足夠小但不屬於同一個 cluster 的 i 和 j  
  189.       if ((cl(i)~=cl(j))&& (dist(i,j)<=dc))  
  190.         rho_aver=(rho(i)+rho(j))/2.; %% 取 i,j 兩點的平均局部密度  
  191.         if (rho_aver>bord_rho(cl(i)))   
  192.           bord_rho(cl(i))=rho_aver;  
  193.         end  
  194.         if (rho_aver>bord_rho(cl(j)))   
  195.           bord_rho(cl(j))=rho_aver;  
  196.         end  
  197.       end  
  198.     end  
  199.   end  
  200.   
  201.   %% halo 值爲 0 表示爲 outlier  
  202.   for i=1:ND  
  203.     if (rho(i)<bord_rho(cl(i)))  
  204.       halo(i)=0;  
  205.     end  
  206.   end  
  207.   
  208. end  
  209.   
  210. %% 逐一處理每個 cluster  
  211. for i=1:NCLUST  
  212.   nc=0; %% 用於累計當前 cluster 中數據點的個數  
  213.   nh=0; %% 用於累計當前 cluster 中核心數據點的個數  
  214.   for j=1:ND  
  215.     if (cl(j)==i)   
  216.       nc=nc+1;  
  217.     end  
  218.     if (halo(j)==i)   
  219.       nh=nh+1;  
  220.     end  
  221.   end  
  222.   
  223.   fprintf('CLUSTER: %i CENTER: %i ELEMENTS: %i CORE: %i HALO: %i \n', i,icl(i),nc,nh,nc-nh);  
  224.   
  225. end  
  226.   
  227. cmap=colormap;  
  228. for i=1:NCLUST  
  229.    ic=int8((i*64.)/(NCLUST*1.));  
  230.    subplot(2,1,1)  
  231.    hold on  
  232.    plot(rho(icl(i)),delta(icl(i)),'o','MarkerSize',8,'MarkerFaceColor',cmap(ic,:),'MarkerEdgeColor',cmap(ic,:));  
  233. end  
  234. subplot(2,1,2)  
  235. disp('Performing 2D nonclassical multidimensional scaling')  
  236. Y1 = mdscale(dist, 2, 'criterion','metricstress');  
  237. plot(Y1(:,1),Y1(:,2),'o','MarkerSize',2,'MarkerFaceColor','k','MarkerEdgeColor','k');  
  238. title ('2D Nonclassical multidimensional scaling','FontSize',15.0)  
  239. xlabel ('X')  
  240. ylabel ('Y')  
  241. for i=1:ND  
  242.  A(i,1)=0.;  
  243.  A(i,2)=0.;  
  244. end  
  245. for i=1:NCLUST  
  246.   nn=0;  
  247.   ic=int8((i*64.)/(NCLUST*1.));  
  248.   for j=1:ND  
  249.     if (halo(j)==i)  
  250.       nn=nn+1;  
  251.       A(nn,1)=Y1(j,1);  
  252.       A(nn,2)=Y1(j,2);  
  253.     end  
  254.   end  
  255.   hold on  
  256.   plot(A(1:nn,1),A(1:nn,2),'o','MarkerSize',2,'MarkerFaceColor',cmap(ic,:),'MarkerEdgeColor',cmap(ic,:));  
  257. end  
  258.   
  259. %for i=1:ND  
  260. %   if (halo(i)>0)  
  261. %      ic=int8((halo(i)*64.)/(NCLUST*1.));  
  262. %      hold on  
  263. %      plot(Y1(i,1),Y1(i,2),'o','MarkerSize',2,'MarkerFaceColor',cmap(ic,:),'MarkerEdgeColor',cmap(ic,:));  
  264. %   end  
  265. %end  
  266. faa = fopen('CLUSTER_ASSIGNATION', 'w');  
  267. disp('Generated file:CLUSTER_ASSIGNATION')  
  268. disp('column 1:element id')  
  269. disp('column 2:cluster assignation without halo control')  
  270. disp('column 3:cluster assignation with halo control')  
  271. for i=1:ND  
  272.    fprintf(faa, '%i %i %i\n',i,cl(i),halo(i));  
  273. end  


本系列聚類算法的其他鏈接

第一章  引言

第二章  預備知識

第三章  直接聚類法

第四章  K-means

第五章  DBSCAN

第六章  OPTICS

第七章 聚類分析的效果評測

第八章 數據尺度化問題

原作者: peghoty 

轉載者:AimAtFuture

出處: http://blog.csdn.net/itplus/article/details/38926837

歡迎轉載/分享, 但請務必聲明文章出處. 請尊重原作者的勞動!

發佈了59 篇原創文章 · 獲贊 17 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章