聚类算法的设计与实现
常用的聚类算法有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 }
作者:wj704
出处:http://www.cnblogs.com/wj204/