zoukankan      html  css  js  c++  java
  • K-means基础入门(c语言)

      K-means聚类算法是一种实现起来相对简单,应用广泛的迭代求解的聚类分析算法。其步骤是随机选取K个对象作为初始的聚类中心,然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。每分配一个样本,聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是没有(或最小数目)对象被重新分配给不同的聚类,没有(或最小数目)聚类中心再发生变化,误差平方和局部最小。(以上来自百度百科)

      简单来说,假设有一堆点杂糅在一起,想要将其中的不同类型的点区分开来归类,就可以使用K-means算法来简单实现。K-means聚类算法进行区分两种点阵

      图a中有一堆随机的杂糅在一起的点阵,图b中我们随机选择了两个质心(即画叉叉的位置),然后在图c中分别求点阵中所有点到这两个叉叉的距离,记录下每个点距离哪个叉叉最近,对应的叉叉是什么颜色(即将这个点进行初步的归类),每个点与红色叉叉和蓝色叉叉的距离计算出来后,得到了所有样本点的第一轮迭代后的类别。此时我们对当前标记为红色和蓝色的点分别求其新的质心(叉叉),如图d所示,新的红色叉叉和蓝色叉叉的位置已经发生了变动。持续多次重复前面我们对每个点计算距离的过程(即将所有点的类别标记为距离最近的质心的类别并求新的质心)。最后,我们就能得到两种不同类别的点阵。

    K-Means算法流程

    算法步骤:

    1.(随机)选择K个聚类的初始中心;

    2.对任意一个样本点,求其到K个聚类中心的距离,将样本点归类到距离最小的中心的聚类,如此迭代n次;

    3.每次迭代过程中,利用均值等方法更新各个聚类的中心点(质心);

    4.对K个聚类中心,利用2,3步迭代更新后,如果位置点变化很小(可以设置阈值),则认为达到稳定状态,迭代结束,对不同的聚类块和聚类中心可选择不同的颜色标注。

    样本与质点距离的计算公式(欧氏距离)

    二维空间的公式

       

    其中,  为点 与点  之间的欧氏距离;  为点 (x2,y2)到原点的欧氏距离。

    三维空间的公式

          

    n维空间的公式

    代码段

     假定这些点阵是待区分的样本点:

     

    设置两个中心点方便进行分类

    这里是手动设置的中心点,如果使用随机进行生成中心点,中心点的生成会出现乱码

     

     通过计算每个阵点与中心点的最短距离进而实现归类

     这里计算平方误差进而比较决定是否继续迭代的原因我不是很明白,希望有懂得大佬能在评论区教一下我(,,・ω・,,)。

     

    运行结果

     

    完整代码

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include <math.h>
      5 #include <time.h>
      6  
      7 #define N 11
      8 #define K 2 
      9  
     10 typedef struct
     11 {
     12     float x;
     13     float y;
     14 }Point;
     15  
     16 int center[N];  //  判断每个点属于哪个簇
     17  
     18 Point point[N] = {
     19     {2.0, 10.0},
     20     {2.0, 5.0},
     21     {8.0, 4.0},
     22     {5.0, 8.0},
     23     {7.0, 5.0},
     24     {6.0, 4.0},
     25     {1.0, 2.0},
     26     {4.0, 9.0},
     27     {7.0, 3.0},
     28     {1.0, 3.0},
     29     {3.0, 9.0}
     30 };
     31  
     32 Point mean[K];  // 保存每个簇的中心点
     33  
     34 float getDistance(Point point1, Point point2)   //计算样本点与质点的距离 
     35 {
     36     float d;
     37     d = sqrt((point1.x - point2.x) * (point1.x - point2.x) + (point1.y - point2.y) * (point1.y - point2.y));
     38     return d;
     39 }
     40  
     41 // 计算每个簇的中心点
     42 void getMean(int center[N])
     43 {
     44     Point tep;
     45     int i, j, count = 0;
     46     for(i = 0; i < K; ++i)
     47     {
     48         count = 0;
     49         tep.x = 0.0;   // 每算出一个簇的中心点值后清0
     50         tep.y = 0.0;
     51         for(j = 0; j < N; ++j)
     52         {
     53             if(i == center[j])
     54             {
     55                 count++;
     56                 tep.x += point[j].x;
     57                 tep.y += point[j].y;       //将同一类别的样本点归类到一起 
     58             }
     59         }
     60         tep.x /= count;
     61         tep.y /= count;
     62         mean[i] = tep;  //保存每个簇的中心点 
     63     }
     64     for(i = 0; i < K; ++i)
     65     {
     66         printf("对于类别 %d 其新的中心质点是 : 	( %f, %f )
    ", i+1, mean[i].x, mean[i].y);
     67     }
     68 }
     69  
     70 // 计算平方误差函数
     71 float getE()
     72 {
     73     int i, j;
     74     float cnt = 0.0, sum = 0.0;
     75     for(i = 0; i < K; ++i)
     76     {
     77         for(j = 0; j < N; ++j)
     78         {
     79             if(i == center[j])
     80             {
     81                 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);
     82                 sum += cnt;
     83             }
     84         }
     85     }
     86     return sum;
     87 }
     88  
     89 /// 把N个点聚类
     90 void cluster()
     91 {
     92     int i, j, q;
     93     float min;
     94     float distance[N][K];
     95     for(i = 0; i < N; ++i)
     96     {
     97         min = 999999.0;
     98         for(j = 0; j < K; ++j)
     99         {
    100             distance[i][j] = getDistance(point[i], mean[j]);    //调用计算样本点与质点的距离的函数 
    101  
    102         }
    103         for(q = 0; q < K; ++q)
    104         {
    105             if(distance[i][q] < min)
    106             {
    107                 min = distance[i][q];
    108                 center[i] = q;      //将最小距离所属的质点赋值给对应的样本点 
    109             }
    110         }
    111         printf("( %.0f, %.0f )	 该点所属的类别为——%d
    ", point[i].x, point[i].y, center[i] + 1);
    112     }
    113     printf("-----------------------------
    ");
    114 }
    115  
    116 int main()
    117 {
    118     int i, j, count = 0;
    119     float temp1;
    120     float temp2, t;
    121     printf("----------待分类的阵点----------
    ");
    122     for(i = 0; i < N; ++i)
    123     {
    124         printf("	( %.0f, %.0f )
    ", point[i].x, point[i].y);
    125     }
    126     printf("-----------------------------
    ");
    127  
    128 
    129 
    130     mean[0].x = point[1].x;      // 初始化k个中心点(这里我们做两个中心点即红色和蓝色2两种类别) 
    131     mean[0].y = point[2].y;
    132  
    133     mean[1].x = point[4].x;
    134     mean[1].y = point[5].y;
    135   
    136 
    137 
    138  
    139     cluster();          // 第一次根据预设的k个点进行聚类
    140     
    141     temp1 = getE();        //  第一次平方误差
    142     count++;                   //  计算形成最终的簇用了多少次
    143     printf("第1次平方误差为: %f
    
    ", temp1);
    144  
    145     getMean(center);   //计算每个簇的新的中心点 
    146     
    147     cluster();            // 第二次根据预设的k个点进行聚类
    148     
    149     temp2 = getE();        //  根据簇形成新的中心点,并计算出平方误差
    150     count++;                //  计算形成最终的簇用了多少次
    151     printf("第2次平方误差为: %f
    
    ", temp2);
    152  
    153     while(fabs(temp2 - temp1) != 0)   //  比较两次平方误差 判断是否相等,不相等继续迭代
    154     {
    155         temp1 = temp2;
    156         getMean(center);
    157         cluster();
    158         temp2 = getE();
    159         count++;
    160         printf("第%d次平方误差为: %f
    ", count, temp2);
    161     }
    162  
    163     printf("总共的迭代次数为: %d
    
    ", count);  // 统计出迭代次数
    164     system("pause");
    165     return 0;
    166 }

    参考网址:

    https://blog.csdn.net/weixin_42029738/article/details/81978038

    https://blog.csdn.net/enter89/article/details/90349943

    https://baike.baidu.com/item/K%E5%9D%87%E5%80%BC%E8%81%9A%E7%B1%BB%E7%AE%97%E6%B3%95/15779627?fromtitle=K-means&fromid=4934806&fr=aladdin

    代码参考https://blog.csdn.net/triumph92/article/details/41128049?tdsourcetag=s_pcqq_aiomsg

  • 相关阅读:
    Git 基础
    SharePoint 2013 对象模型操作"网站设置"菜单
    SharePoint 2013 隐藏部分Ribbon菜单
    SharePoint 2013 Designer系列之数据视图筛选
    SharePoint 2013 Designer系列之数据视图
    SharePoint 2013 Designer系列之自定义列表表单
    SharePoint 2013 设置自定义布局页
    SharePoint 2013 "通知我"功能简介
    SharePoint 2013 创建web应用程序报错"This page can’t be displayed"
    SharePoint 禁用本地回环的两个方法
  • 原文地址:https://www.cnblogs.com/bokeyuancj/p/11460883.html
Copyright © 2011-2022 走看看