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 
011typedef struct {
012    double p[NA];
013    double distance[K];
014}Point;
015 
016typedef 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/* 声明函数 */
026int Is_equal(int a[], int n, int b);
027double Euclid(int x, int y);
028void input_data();
029void Init_center();
030void calculate_distance();
031void Make_new_cluster();
032void Make_new_center();
033void output_info(int flag);
034 
035 
036Point all_data[Psize];      /* 数据大小 */
037Pop 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 ***********************************************/
048void 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 **************************************************/
070void 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 *********************************/
095int 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 *******************************************/
106void 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 ***********************************************/
120double 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 ***********************/
135void 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 ************************************************/
170void 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 *******************************/
197void 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 *******************************/
226int 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}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值