计算智能——K-means聚类算法的原理和实现(C语言)

计算智能——K-means聚类算法的原理和实现(C语言)

算法定义

k-means聚类算法是一种迭代求解的聚类分析算法。,
k均值聚类是最著名的划分聚类算法,由于简洁和效率使得他成为所有聚类算法中最广泛使用的。给定一个数据点集合和需要的聚类数目k,k由用户指定,k均值算法根据某个距离函数反复把数据分入k个聚类中。

算法原理

k-means算法首先选取k个点作为初始的聚类中心,然后计算各个样本到各聚类中心的距离,把每个样本归入离它最近的那个聚类中心所在的类; 调整后的新类计算新的聚类中心,如果相邻两次的聚类中心没有任何变化,这说明数据对象调整结束,聚类准则函数f已经收敛。在每次迭代过程中都要考察每个样本的分类是否正确,若不正确,就要调整。在全部数据调整完后,再修改聚类中心,进入下一次迭代。如果在某一次迭代算法中,所有的数据 对象被正确分类,则不会有调整,聚类中心也不会有任何变化,这标志着f已经收敛,算法结束。该算法可分为四个步骤

  1. 选定k个中心点,选定n个样本,输入这些样本。
  2. 为每个样本找到距离其最近的中心点(寻找组织),距离同一中心点最近的点为一个类,这样完成了一次聚类。
  3. 判断聚类前后的样本点的类别情况是否相同(及两次聚类的平方误差是否相同),如果相同,则算法结束,否则进入第四步。
  4. 针对每个类别中的样本点,计算这些样本的中心点,以此作为该类新的中心点,继续第二步。

算法流程图

这是

算法实现

       #include <stdio.h>
        #include <string.h>
        #include <stdlib.h>
        #include <math.h>
        #include <time.h>
        #define max 100
        typedef struct
        {
        	float x;
        	float y;
        }Point;
        Point point[max];
        Point mean[max];  ///  保存每个簇的中心点
        
        int center[max];  ///  判断每个点属于哪个簇
        int Num;
        int K;
         
        //获得两点间直线距离 
        float getDistance(Point point1, Point point2)
        {
        	float d;
        	d = sqrt((point1.x - point2.x) * (point1.x - point2.x) + (point1.y - point2.y) * (point1.y - point2.y));
        	return d;
        }
         
        // 计算每个簇的中心点 把归属于该中心点的点相加除以点数 
        void getMean(int center[max])
        {
        	Point tep;
        	int i, j, count = 0;
        	for(i = 0; i < K; i++)
        	{
        		count = 0;
        		tep.x = 0.0;   /// 每算出一个簇的中心点值后清0
        		tep.y = 0.0;
                for(j = 0; j < Num; j++)
        		{
        			if(i == center[j])
        			{
        				count++;
        				tep.x += point[j].x;
        				tep.y += point[j].y;
        			}
        		}
        		tep.x /= count;
        		tep.y /= count;
        		mean[i] = tep;
        	}
        	for(i = 0; i < K; i++)
            {
            	printf("The new center point of %d is : \t( %f, %f )\n", i+1, mean[i].x, mean[i].y);
            }
        }
         
        /// 计算平方误差函数(x1-x2)^2+(y1-y2)^2  计算当前各点与当前所属中心点间距离误差  
        float getError()
        {
        	int i, j;
        	float cnt = 0.0, sum = 0.0;
        	for(i = 0; i < K; i++)
        	{
        		for(j = 0; j < Num; j++)
        		{
        			if(i == center[j])
        			{
        				cnt = (point[j].x - mean[i].x) * (point[j].x - mean[i].x) + (point[j].y - mean[i].y) * (point[j].y - mean[i].y);
        				sum += cnt;
        			}
        		}
        	}
        	return sum;
        }
         
        // 把Num个点聚类
        void cluster()
        {
        	int i, j, q;
        	float min;
        	float distance[Num][K];
        	for(i = 0; i < Num; i++)
        	{
        		min = 9999.0;
        		//获得(point[i].x,point[i].y)的点到每个中心点的距离 
        		for(j = 0; j < K; j++)
        		{
        			distance[i][j] = getDistance(point[i], mean[j]);
        		}
        		//计算每个点到三个中心点的距离,如果发现有直线距离更短的中心点,则将自己归入其中,放弃当前中心点 
        		for(q = 0; q < K; q++)
        		{
        			if(distance[i][q] < min)
        			{
        				min = distance[i][q];
                		center[i] = q;
        			}
        		}
        		//输出这个过程中的该点及其归类 
        		printf("( %.0f, %.0f )\t in cluster %d\n", point[i].x, point[i].y, center[i] + 1);
        	}
        	printf("-----------------------------\n");
        }
         
        int main()
        {
            int i, j, n = 0;
            float temp1;
            float temp2, t;
            printf("Please input the num:\n");
            scanf("%d", &Num); 
            printf("Please input the k:\n");
            scanf("%d", &K);
            printf("Please input %d coordinates:\n",Num);
            for(i = 0; i < Num; i++){
            	scanf("%f%f",&point[i].x,&point[i].y);
        	}
           
            printf("-----------------------------\n");
         
    		for(i = 0;i < K ; i++){
              	mean[i].x = point[i].x;      /// 初始化k个中心点
              	mean[i].y = point[i].y;
         	 }
         
            cluster();          /// 第一次根据预设的k个点进行聚类
            temp1 = getError();        ///  第一次平方误差
            n++;                   ///  n计算形成最终的簇用了多少次
         
            printf("The square error on 1 is: %f\n\n", temp1);
         
            getMean(center);
            cluster();
            temp2 = getError();        ///  根据簇形成新的中心点,并计算出平方误差
            n++;
         
            printf("The square error on 2 is: %f\n\n", temp2);
         
            while(fabs(temp2 - temp1) != 0)   ///  比较两次平方误差 判断是否相等,不相等继续迭代
            {
            	temp1 = temp2;
                getMean(center);
            	cluster();
            	temp2 = getError();
            	n++;
            	printf("The square error on %d is: %f\n", n, temp2);
            }
         
            printf("The total round of cluster is: %d\n\n", n);  /// 统计出迭代次数
            system("pause");
            return 0;
        } 

参考资料

Polykovskiy, D. and Novikov, A., Bayesian Methods for Machine Learning

发布了12 篇原创文章 · 获赞 5 · 访问量 1114

猜你喜欢

转载自blog.csdn.net/lzydelyc/article/details/100637003