发表在 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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章