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

  • 相关阅读:
    如何让create-react-app锦上添花,满足实际需求?
    《漫画算法》笔记-下篇
    《漫画算法》笔记-上篇
    react + typescript 学习
    node http 模块 常用知识点记录
    vue 相关技术文章集锦
    读后感:数据结构与算法JavaScript描述
    css 揭秘-读书笔记
    vue-textarea 自适应高度
    消除浏览器对input的自动填充
  • 原文地址:https://www.cnblogs.com/bokeyuancj/p/11460883.html
Copyright © 2011-2022 走看看