`
wbj0110
  • 浏览: 1550325 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

K-MEANS算法

阅读更多

1. [代码][C/C++/Objective-C]代码    

001 #include <stdio.h>
002 #include <stdlib.h>
003 #include <math.h>
004  
005 #define NA  4       /* 数据维数 */
006 #define K   3       /* 聚类数 */
007 #define Psize   50      /* 种群大小 */
008 #define T   30      /* 最大迭代数 */
009 #define ED  0.0000001   /* 结束条件 */
010  
011 typedef struct {
012     double p[NA];
013     double distance[K];
014 }Point;
015  
016 typedef struct {
017     Point clu_cent[K];  /* 即cluster_center 簇类中心 */
018     int cluster[K][Psize];  /* 簇类数组 */
019     int cluster_num[K]; /* 簇类中一组数据的编号 */
020     double fitness;     /* 样本适应度值,用于判断结束条件 */
021     double old_fitness; /* 前一次迭代的适应度值 */
022     double Je;      /* 所有样本的平方误差和 */
023 }Pop;
024  
025 /* 声明函数 */
026 int Is_equal(int a[], int n, int b);
027 double Euclid(int x, int y);
028 void input_data();
029 void Init_center();
030 void calculate_distance();
031 void Make_new_cluster();
032 void Make_new_center();
033 void output_info(int flag);
034  
035  
036 Point all_data[Psize];      /* 数据大小 */
037 Pop pop;
038  
039 /************************************************
040  * 从外部文件导入数据,对于没有数据文件将报错, *
041  * 数据文件的格式根据 NA 决定,例如NA = 4时,测 *
042  * 试数据为四维,则test.data 为:     *
043  *  1   2   3   4       *
044  *  1.0 1.2 1.3 1.4     *
045  *      ......              *
046  *      ......              *
047  ***********************************************/
048 void input_data()
049 {
050     FILE *infile;
051     int i, j;
052     double data;
053  
054     if((infile = fopen("test.data", "r")) == NULL){
055         printf("没有test.data这个文件,无法导入数据\n");
056         exit(1);
057     }
058     for(i = 0; i < Psize; i++)
059         for(j = 0; j < NA; j++){
060             fscanf(infile, "%lf", &data);
061             all_data[i].p[j] = data;
062         //  printf("%d --%d  %lf\n", i, j, all_data[i].p[j]);
063         }
064     fclose(infile);     /* 关闭文件描述符 */
065 }
066  
067 /***************************************************
068  * 随机初始化聚类质心,当随机数有相同时跳过继续执行*
069  **************************************************/
070 void Init_center()
071 {
072     int i, j;
073     int num = 0;
074     int rand_num;
075     int rand_num_tmp[K];
076     /* 随机产生三个0~Psize的数 */
077     while(num < K){
078         rand_num = rand() % Psize;
079         if(!Is_equal(rand_num_tmp, num, rand_num))
080             rand_num_tmp[num++] = rand_num;
081     }
082     for(i = 0; i < K; i++){
083     //  printf("初始化质心%d:\n", i + 1);
084         for(j = 0; j < NA; j++){
085             pop.clu_cent[i].p[j] = all_data[rand_num_tmp[i]].p[j];
086     //      printf("%lf ",pop.clu_cent[i].p[j]);   
087         }
088         printf("\n");
089     }
090 }
091  
092 /**********************************
093  * 检查数据是否有相等,相等返回1 *
094  *********************************/
095 int Is_equal(int a[], int n, int b)
096 {
097     int i;
098     for(i = 0; i < n; i++)
099         if(a[i] == b) return 1;
100     return 0;
101 }
102  
103 /********************************************
104  * 计算Psize组数据到K个质心的欧几里德距离*
105  *******************************************/
106 void calculate_distance()
107 {
108     int i, j;
109     for(i = 0; i < Psize; i++)
110         for(j = 0; j < K; j++){
111             all_data[i].distance[j] = Euclid(i, j);
112 //      printf("%d---%d--- %lf \n", i, j, all_data[i].distance[j]);
113         }
114 }
115  
116 /************************************************
117  * 此函数为欧几里德距离公式函数,此处用于计算*
118  * 一组数据到对应簇中心的欧几里德距离。   *
119  ***********************************************/
120 double Euclid(int x, int y)
121 {
122     int i;
123     double distance = 0;
124     for(i = 0; i < NA; i++){
125         distance += pow((all_data[x].p[i] - pop.clu_cent[y].p[i]), 2);
126     }
127     distance = sqrt(distance);
128     return distance;
129 }
130  
131  
132 /************************
133  * 将数据进行簇集归类 *
134  ***********************/
135 void Make_new_cluster()
136 {
137     int i, j;
138  
139     double min;
140      
141     for(i = 0; i < K; i++)       /* 初始化编号 */
142         pop.cluster_num[i] = 0;
143     for(i = 0; i < Psize; i++){ 
144         int index = 0;
145         min = all_data[i].distance[0];
146         for(j = 1; j < K; j++){      /* 筛选到簇心欧几里德最小的 */
147             if(all_data[i].distance[j] < min){
148                 min = all_data[i].distance[j];
149                 index = j;
150             }
151         }
152         /* 划分簇集 */
153         pop.cluster[index][pop.cluster_num[index]++] = i;  
154     }
155     /* 计算所有样本的平方误差和 */
156     pop.Je = 0;
157     for(i = 0; i < K; i++)
158         for(j = 0; j < pop.cluster_num[i]; j++){
159         /* 样本到簇心的值即为其欧几里德距离 */
160             pop.Je +=pow(all_data[pop.cluster[i][j]].distance[i],2);
161         }
162     pop.old_fitness = pop.fitness;  /* 前一次迭代适应度值 */
163 //  printf("old_fitness = %lf\n", pop.old_fitness);
164     pop.fitness = pop.Je;   /* 所有样本平方误差和即为适应度值 */
165 }
166  
167 /*************************************************
168  * 更新簇心,即求其群类的平均距离为新的簇心  *
169  ************************************************/
170 void Make_new_center()
171 {
172     int i, j, n;
173     double tmp_sum;
174  
175     for(i = 0; i < K; i++)
176         for(j = 0; j < NA; j++){
177             tmp_sum = 0;
178             for(n = 0; n < pop.cluster_num[i]; n++){
179                 /* 第i个簇的第j维数的所有数据和 */
180                 tmp_sum += all_data[pop.cluster[i][n]].p[j];
181             }
182             /* 取平均数得到新的簇中心 */
183             pop.clu_cent[i].p[j] = tmp_sum / pop.cluster_num[i];
184         }
185 }
186  
187 /********************************
188  *  输出信息函数      *              
189  * 显示格式为:       *
190  * 质心K:         *
191  * NA维的质心数据     *
192  * 簇类K:         *
193  * NA维属于簇类K的数据      *
194  *  ......          *
195  *  ......          *
196  *******************************/
197 void output_info(int flag)
198 {
199     int i, j, n;
200  
201  
202     for(i = 0; i < K; i++){ 
203         if(flag == 0){
204             printf("初始化质心%d:\n", i + 1);
205             for(n = 0; n < NA; n++)
206                 printf("%lf ",pop.clu_cent[i].p[n]);
207         } else if(flag == 1){
208             printf("最终质心%d:\n", i + 1);
209             for(n = 0; n < NA; n++)
210                 printf("%lf ",pop.clu_cent[i].p[n]);
211         }
212         printf("\n簇类%d:\n", i + 1);
213         for(j = 0; j < pop.cluster_num[i]; j++){        
214             for(n = 0; n < NA; n++){
215                     printf("%lf ",
216                     all_data[pop.cluster[i][j]].p[n]);
217             }
218             printf("\n");
219         }
220     }
221 }
222  
223 /********************************
224  *      主函数     *
225  *******************************/
226 int main()
227 {
228     int i;
229     double differ = 1;  /* 适应度差值 */
230     int flag = 0;       /* 用来标示是显示初始数据还是聚类后的数据 */
231     input_data();       /* 导入数据 */
232     Init_center();      /* 初始化质心 */
233  
234     for(i = 0; (i < T) && (differ > ED); i++){
235         calculate_distance();       /* 计算欧几里德距离 */
236         Make_new_cluster();     /* 产生新的聚类 */
237         if(flag == 0){
238             output_info(flag);  /* 输出第一次聚类后的结果 */
239             flag = 1;  
240         }
241         Make_new_center();      /* 对新的聚类产生新的质心 */
242         differ = pop.old_fitness - pop.fitness; /* 判断条件 */
243         differ = fabs(differ);
244  
245     //  printf("differ = %lf\n", differ);
246     //  printf("old_fitness = %lf\n", pop.old_fitness);
247     //  printf("fitness = %lf\n", pop.fitness);
248     }
249  
250     printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
251     output_info(flag);  /* 聚类后显示结果 */
252  
253     return 0;
254 }
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics