聚类算法的设计与实现

 常用的聚类算法有K-Means(K均值聚类算法)、DBSCAN和OPTICS等。

K均值聚类算法的相关信息自行从网上获取。简单介绍如下:

K-Means算法实质上是一种将聚类视为密度估计问题的概率方法。k-means 算法接受输入量 k ;然后将n个数据对象划分为 k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高;而不同聚类中的对象相似度较小。聚类相似度是利用各聚类中对象的均值所获得一个“中心对象”(引力中心)来进行计算的。

K-Means 算法的步骤:

(1)选K个初始聚类中心,z1(1),z2(1),…,zK(1),其中括号内的序号为寻找聚类中心的迭代运算的次序号。聚类中心的向量值可任意设定,例如可选开始的K个模式样本的向量值作为初始聚类中心。

(2)逐个将需分类的模式样本{x}按最小距离准则分配给K个聚类中心中的某一个zj(1)。假设i=j时,其中k为迭代运算的次序号,第一次迭代k=1,Sj表示第j个聚类,其聚类中心为zj。

(3)计算各个聚类中心的新的向量值,zj(k+1),j=1,2,…,K。求各聚类域中所包含样本的均值向量;其中Nj为第j个聚类域Sj中所包含的样本个数。以均值向量作为新的聚类中心,可使如下聚类准则函数最小:在这一步中要分别计算K个聚类中的样本均值向量,所以称之为K-均值算法。

(4)若j=1,2,…,K,则返回第二步,将模式样本逐个重新分类,重复迭代运算;

若本次迭代与前次的质心聚合相等,即已收敛,计算结束。

实现代码(参考自http://blog.csdn.net/blue4689/article/details/6629488):
  1 #include <stdio.h> 
  2 #include <math.h>
  3 #include <stdlib.h>
  4 #include <time.h>
  5 #define TRUE            1
  6 #define FALSE           0 
  7 int N;//数据个数
  8 int K;//集合个数
  9 int * CenterIndex;//初始化质心数组的索引
 10 double * Center;//质心集合
 11 double * CenterCopy;//质心集合副本
 12 double * AllData;//数据集合
 13 double ** Cluster;//簇的集合
 14 int * Top;//集合中元素的个数,也会用作栈处理
 15 
 16  
 17 //随机生成k个数x(0<=x<=n-1)作为起始的质心集合
 18 void CreateRandomArray(int n, int k,int * center)
 19 {
 20     int i=0;
 21     int j=0;    
 22     srand( (unsigned)time( NULL ) );
 23     for( i=0;i<k;++i)//随机生成k个数
 24     {
 25         int a=rand()%n;
 26         //判重
 27         for(j=0;j<i;j++)
 28         {
 29             if(center[j]==a)//重复
 30             {
 31                 break;
 32             }
 33         }
 34         if(j>=i)//如果不重复,加入
 35         {
 36             center[i]=a;
 37         }
 38         else
 39         {
 40             i--;
 41             //如果重复,本次重新随机生成
 42         }
 43     }     
 44 }
 45  
 46 //返回距离最小的质心的序号
 47 int GetIndex(double value,double * center)
 48 {
 49     int i=0;
 50     int index=i;//最小的质心序号
 51     double min=fabs(value-center[i]);//距质心最小距离
 52     for(i=0;i<K;i++)
 53     {
 54         if(fabs(value-center[i])<min)//如果比当前距离还小,更新最小的质心序号和距离值
 55         {
 56              index=i;
 57              min=fabs(value-center[i]);
 58         }
 59     }
 60     return index;
 61 }
 62  
 63 //拷贝质心数组到副本
 64 void CopyCenter()
 65 {
 66     int i=0;
 67     for(i=0;i<K;i++)
 68     {
 69         CenterCopy[i]=Center[i];
 70     }
 71 }
 72 //初始化质心,随机生成法
 73 void InitCenter()
 74 {
 75     int i=0;
 76     CreateRandomArray(N,K,CenterIndex);//产生随机的K个<N的不同的序列
 77     for(i=0;i<K;i++)
 78     {
 79         Center[i]=AllData[CenterIndex[i]];//将对应数据赋值给质心数组
 80     }
 81     CopyCenter();//拷贝到质心副本
 82 }
 83 //加入一个数据到一个Cluster[index]集合
 84 void AddToCluster(int index,double value)
 85 {
 86     Cluster[index][Top[index]++]=value;//这里同进栈操作
 87 } 
 88 
 89 //重新计算簇集合
 90 void UpdateCluster()
 91 {    
 92     int i=0;
 93     int tindex;
 94     //将所有的集合清空,即将TOP置0
 95     for(i=0;i<K;i++)
 96     {
 97         Top[i]=0;
 98     }
 99     for(i=0;i<N;i++)
100     {
101         tindex=GetIndex(AllData[i],Center);//得到与当前数据最小的质心索引
102         AddToCluster(tindex,AllData[i]); //加入到相应的集合中 
103     }
104 }
105 //重新计算质心集合,对每一簇集合中的元素加总求平均即可
106 void UpdateCenter()
107 {
108     int i=0;
109     int j=0;
110     double sum=0;
111     for(i=0;i<K;i++)
112     {
113         sum=0;    
114         //计算簇i的元素和
115         for(j=0;j<Top[i];j++)
116          {
117              sum+=Cluster[i][j];
118          }
119         if(Top[i]>0)//如果该簇元素不为空
120         {
121            Center[i]=sum/Top[i];//求其平均值
122         }
123     }
124 }
125 //判断2数组元素是否相等
126 int IsEqual(double * center1 ,double * center2)
127 {
128     int i;
129     for(i=0;i<K;i++)
130     {
131          if(fabs(center1[i]!=center2[i]))
132          {
133              return FALSE;
134          }
135     }
136     return TRUE;
137 }
138 //打印聚合结果
139 void Print()
140 {
141     int i,j;
142     printf("-------------------------------------- \n");
143     for(i=0;i<K;i++)
144     {
145          printf("第%d组: 质心(%f)\t",i,Center[i]);
146           for(j=0;j<Top[i];j++)
147           {
148               printf("%f\t",Cluster[i][j]);
149           }  
150           printf("\n");
151     }     
152 }
153 //初始化聚类的各种数据
154 void InitData()
155 {
156     int i=0;
157     int a;
158     printf("输入数据个数: ");     
159     scanf("%d",&N);
160     printf("输入簇个数: ");     
161     scanf("%d",&K);    
162     if(K>N)
163     {
164         exit(0);
165     }
166     Center=(double *)malloc(sizeof(double)*K);//为质心集合申请空间
167     CenterIndex=(int *)malloc(sizeof(int)*K);//为质心集合索引申请空间
168     CenterCopy=(double *)malloc(sizeof(double)*K);//为质心集合副本申请空间
169     Top=(int *)malloc(sizeof(int)*K); 
170     AllData=(double *)malloc(sizeof(double)*N);//为数据集合申请空间
171     Cluster=(double **)malloc(sizeof(double *)*K);//为簇集合申请空间
172     //初始化K个簇集合
173     for(i=0;i<K;i++)
174     {
175         Cluster[i]=(double *)malloc(sizeof(double)*N);
176         Top[i]=0;
177     }
178     printf("输入%d数据:\n",N);
179     for(i=0;i<N;i++)
180     {
181         scanf("%d",&(a));
182         AllData[i]=a;
183     }
184     InitCenter();//初始化质心集合      
185     UpdateCluster();//初始化K个簇集合
186      
187 }
188 /*
189 算法描述:
190 K均值算法:
191     给定类的个数K,将N个对象分到K个类中去,
192     使得类内对象之间的相似性最大,而类之间的相似性最小。
193 */
194 main()
195 {
196     int Flag=1;//迭代标志,若为false,则迭代结束
197     int i=0;
198      InitData();//初始化数据      
199      while(Flag)//开始迭代
200      {
201          UpdateCluster();//更新各个聚类
202          UpdateCenter();//更新质心数组
203          if(IsEqual(Center,CenterCopy))//如果本次迭代与前次的质心聚合相等,即已收敛,结束退出
204          {
205              Flag=0;
206          }
207          else//否则将质心副本置为本次迭代得到的的质心集合
208          {
209              CopyCenter();//将质心副本置为本次迭代得到的的质心集合
210          }
211      }
212      Print();//输出结果
213 }
View Code

 


posted @ 2013-06-15 21:58  wj704  阅读(675)  评论(0编辑  收藏  举报