K_means聚类算法

这一期给大家带来的是K_means算法的基础教学及代码实现,如果讲的透彻别忘了收藏,当然,如果遇到任何问题也可以在评论区留言,我将及时回复。
       K_means聚类算法简单来说就是将空间中的数据按照某些特征进行分类,如何分类呢?难点就在于数据量太大,海量空间数据的大小和复杂性都在快速增长,已经远远超出了人们的理解能力,所以从这些空间数据中发现邻域知识迫切需要一些空间聚类分析算法,这些算法将是从海量数据中发现知识的一个重要手段,而在这些空间聚类分析算法中,K-Means算法作为一种无监督的聚类算法,它实现起来比较简单,聚类效果也不错,因此在空间数据分析中应用很广泛,同时也起着重要的作用。

目录

  • K_means聚类算法
    • 一、问题描述
    • 二、问题分析
    • 三、代码实现
      • 1. 数据集从哪儿来?
      • 2. 初始中心点怎么设置?
      • 3. 如何计算数据集中任意两个点的距离?
      • 4. 怎么判断某个数据点从属于哪个类?
      • 5. 怎样计算新的中心点?
      • 6.如何判定是否已经分类完成?
      • 7. 新旧中心点怎样实现更换?
      • 8. 算法的运行结果如何查看?
    • 四、源码
    • 五、代码运行结果
    • 六、常见问题及解决

一、问题描述

首先从数据集中随机选取K个点作为初始聚类中心,然后计算各个样本到聚类中心的距离,把样本点归到离它最近的那个聚类中心所在的类。计算新形成的每一个聚类数据对象的平均值来得到新的聚类中心,如果相邻两次的聚类中心没有任何变化,说明样本调整结束,所有数据已经完成分类。
       因为在迭代过程中数据集的K个中心点在不停的变化,所以在每次迭代过程中都需要对所有的样本点进行重新分类,当中心点不再移动时,此时的分类结果就是最终的结果,这种在迭代过程中不断改变中心点和重新分类的过程,是K-means算法最大的特点。

二、问题分析

算法:K_means
步骤:
(1)对于要分类的数据集,任意从其中选择K个点作为初始的聚类中心点;
(2)计算数据集中每个点到中心点的距离,根据距离将其划分到对应的聚类中;
(3)计算聚类中所有点的中心点,作为新的聚类中心点;
(4)判断新的中心点与旧的中心点之间的距离是否符合要求,不符合则返回步骤(2),直到两个中心点距离相差符合要求。

三、代码实现

1. 数据集从哪儿来?

为了方便理解,我们举个例子:
小欣是一个女孩子,有一组三围数据:88,68,94,那么我们可以将这组数据用一个三维的点来表示(88,68,94),如果有很多女孩子,那么我们就可以用(86,66,90)(84,64,86)……等多个点来表示,这么多个点放在一起,就构成了一个数据集,而每个点上的维度(三围可以看成是x,y,z三个坐标),就表示了现实中的采集到的几个特征点。

这种以点的维度来表示现实物体特征的方法很常用,我们本次算法便利用这种原理。

假设我们的数据集中有50个点,且每个点都是3维的,那么就可以构建一个二维数组dataSet[50][3],生成这个数组原始数据的过程,就是获得数据集的过程。

当然我们不可能真的就找50个三围一个个输入,那太可怕了,为了快速获取原始数据,我们将直接使用随机函数(产生0到100之间的数)对这个二维数组进行填充。

    for (int i = 0; i < volume; ++i) {      // Randomly generate 50 3D coordinate pointsfor (int j = 0; j < dimension; ++j) {dataSet[i][j] = rand()%100;     //the random figure between 0 - 10}}

(代码中volume为数据集的容量,即50,dimension为点的维度,即3)

2. 初始中心点怎么设置?

初始中心点怎么设置?这个问题可以拆分成两个小问题:

–>第一个问题是:我们设置几个中心点?
为了方便展示,我们仅设置3个中心点,预计将100个点分为三个类;

–>第二个问题是:这个中心点怎么赋初值?
因为中心点要来回移动,我们需要有3个新中心点和3个旧中心点的位置,即我们可以在dataSet数组后边再扩展6个位置,即50,51,52三个点代表旧的中心点,53,54,55三个点代表新的中心点,新中心点可以直接赋初值为(0,0,0)(0,0,0)(0,0,0),旧中心点可以从前边50个点中随机找三个点把其值复制过来。

    for (int i = 0; i < 3; ++i) {int randNum = rand()%volume;for (int j = 0; j < dimension; ++j)         // Randomly select 3 points which have exited as the center point(50,51,52)dataSet[volume + i][j] = dataSet[randNum][j];for (int j = 0; j < dimension; ++j)         // the 3 new center points set are 0(53,54,55)dataSet[volume + i + 3][j] = 0;}
3. 如何计算数据集中任意两个点的距离?

前边的两个问题解决了数据集的由来以及中心点的确立,因为数据集上的点都要分别和每个中心点比较,那么怎么计算点与点之间的距离呢?

是的,或许你想到了,计算两个点之间的距离,这是初中知识:

double dist(int point_1, int point_2, double dataSet[][dimension]){     //Calculate the distance between two pointsdouble distx = dataSet[point_1][0] - dataSet[point_2][0];double disty = dataSet[point_1][1] - dataSet[point_2][1];double distz = dataSet[point_1][2] - dataSet[point_2][2];double dist = sqrt(distx*distx + disty*disty + distz*distz);return dist;
}
4. 怎么判断某个数据点从属于哪个类?

归类问题我们可以转化为比较距离的问题,因为一个点到每个中心点的距离是不一样的,我们按照离哪个中心点距离最短的原则,把这个点化为那一类;

这里给出一个比较最短距离的函数,并返回编号(50-A类-0,51-B类-1,52-C类-2):

int minDist(double dist_1, double dist_2, double dist_3){       //Calculate which distance is the shortestif(dist_1 <= dist_2 && dist_1 <= dist_3)return 0;       //belong to class Aif(dist_2 <= dist_1 && dist_2 <= dist_3)return 1;       //belong to class Bif(dist_3 <= dist_1 && dist_3 <= dist_2)return 2;       //belong to class
}

能计算两点之间的距离,能判断距离哪个中心点最近,接下来我们需要3个数组来存储划分到三个类中的点:

   int class_A[volume], class_B[volume], class_C[volume];

注意,这三个数组最大容量我设置的都是50,那么肯定存不满,如果存不满的话后期怎么取出里边的内容呢?因此对这三个数组初始化很重要(都初始化为-1,从数组取数字的时候,可以根据-1设置终止条件):

for (int i = 0; i < volume; ++i) {class_A[i] = -1;class_B[i] = -1;class_C[i] = -1;}

数据集中的一个点分别和三个中心点计算距离,产生的结果用minDist函数确定距离哪个中心点最近,并存入对应的类中,这是对一个点需要完成的操作,操作完成后,进行下一个点的操作,直到所有点都完成了一轮的分类。

5. 怎样计算新的中心点?

每一轮所有点都完成分类后,三个类(class_A,class_B,class_C三个数组)中已经存放了分类好的点,那么如何计算新的中心点?
拿class_A类来说,最直接的办法就是把A类中所有点的x坐标相加求平均值,得到新的x坐标,所有点的y坐标相加求平均值,得到新的y坐标,所有点的z坐标相加求平均值,得到新的z坐标;
同样的方法,也可以求出class_B和class_C两个类的新中心点:

void newCenter(const int class[volume], double dataSet[][dimension], int num){        //calculate the new center pointdouble x = 0, y = 0, z = 0;                 //num is mean which new center pointfor (int i = 0; class[i] != -1; ++i) {      // class must be initialized with -1x += dataSet[class[i]][0];y += dataSet[class[i]][1];z += dataSet[class[i]][2];}double Average_x = x/volume;double Average_y = y/volume;double Average_z = z/volume;dataSet[volume + 3 + num][0] = Average_x;dataSet[volume + 3 + num][1] = Average_y;dataSet[volume + 3 + num][2] = Average_z;
}

当然,计算出了新的中心点,就需要把它存储进dataSet数组中,即53,54,55位置。

6.如何判定是否已经分类完成?

对于A类,计算A类新中心点与旧中心点的距离(即50与53求距离),若距离小于0.0005,则A类已经聚合;
对于B类,计算B类新中心点与旧中心点的距离(即51与54求距离),若距离小于0.0005,则B类已经聚合;
对于C类,计算C类新中心点与旧中心点的距离(即52与55求距离),若距离小于0.0005,则C类已经聚合;
当上边三个类都聚合后,数据集的分类已经完成,否则就开启下一轮迭代。

7. 新旧中心点怎样实现更换?

计算出了新的中心点后,若还需进行下一轮迭代,则需要把这几个中心点赋值到旧中心点的位置上(一方面是计算需要,另一方面也是53,54,55位置要空出来留给下一次产生中心点的需要),通俗的说,就是50 = 53, 51 = 54, 52 = 55

void refreshCenter(double dataSet[][3]) {       //refresh the old center pointsfor (int i = 0; i < 3; ++i)for (int j = 0; j < dimension; ++j)dataSet[volume + i][j] = dataSet[volume + i + 3][j];
}
8. 算法的运行结果如何查看?

大家可能最关注的就是查看结果了,是的,有些算法只是一个逻辑模型,必须运用于场景中才能观察到效果,但这里我用C程序设计实现的K_means算法可以查看到结果:

void show(const int class[], double dataSet[][dimension], int num){        //output the result of the K_meanschar className = '\0';if(num == 0)   className = 'A';else if(num == 1)   className = 'B';else if(num == 2)   className = 'C';for (int i = 0; class[i] != -1; ++i)printf("(%f,%f,%f)->%c\n", dataSet[class[i]][0], dataSet[class[i]][1], dataSet[class[i]][2], className);
}

好了,讲解部分已经完毕,你可以尝试用自己的方法将上边的代码串起来,当然也可以借鉴一下我下边的源码,如有问题欢迎留言。

四、源码

#include <stdio.h>
#include "time.h"
#include "stdlib.h"
#include "math.h"#define volume 50          //the data set's volume
#define dimension   3      //the dimension
#define condition 0.0005    //Conditions for data convergencevoid init(double dataSet[][dimension]){     // Initialize the data setsrand((unsigned)time(NULL));for (int i = 0; i < volume; ++i) {      // Randomly generate 50 3D coordinate pointsfor (int j = 0; j < dimension; ++j) {dataSet[i][j] = rand()%100;     //the random figure between 0 - 10}}for (int i = 0; i < 3; ++i) {int randNum = rand()%volume;for (int j = 0; j < dimension; ++j)         // Randomly select 3 points which have exited as the center point(50,51,52)dataSet[volume + i][j] = dataSet[randNum][j];for (int j = 0; j < dimension; ++j)         // the 3 new center points set are 0(53,54,55)dataSet[volume + i + 3][j] = 0;}
}double dist(int point_1, int point_2, double dataSet[][dimension]){     //Calculate the distance between two pointsdouble distx = dataSet[point_1][0] - dataSet[point_2][0];double disty = dataSet[point_1][1] - dataSet[point_2][1];double distz = dataSet[point_1][2] - dataSet[point_2][2];double dist = sqrt(distx*distx + disty*disty + distz*distz);return dist;
}int minDist(double dist_1, double dist_2, double dist_3){       //Calculate which distance is the shortestif(dist_1 <= dist_2 && dist_1 <= dist_3)return 0;       //belong to class Aif(dist_2 <= dist_1 && dist_2 <= dist_3)return 1;       //belong to class Bif(dist_3 <= dist_1 && dist_3 <= dist_2)return 2;       //belong to class
}int judge(double dataSet[][dimension]){     //Judge whether the new and old center points have changeddouble dist_center1 = dist(volume, volume + 3, dataSet);double dist_center2 = dist(volume + 1, volume + 4, dataSet);double dist_center3 = dist(volume + 2, volume + 5, dataSet);if(dist_center1 > condition || dist_center2 > condition || dist_center3 > condition)return 1;       //Any one greater than 0.005 will be judged as non-convergentelsereturn 0;       //The data set has converged
}void newCenter(const int class[volume], double dataSet[][dimension], int num){        //calculate the new center pointdouble x = 0, y = 0, z = 0;                 //num is mean which new center pointfor (int i = 0; class[i] != -1; ++i) {      // class must be initialized with -1x += dataSet[class[i]][0];y += dataSet[class[i]][1];z += dataSet[class[i]][2];}double Average_x = x/volume;double Average_y = y/volume;double Average_z = z/volume;dataSet[volume + 3 + num][0] = Average_x;dataSet[volume + 3 + num][1] = Average_y;dataSet[volume + 3 + num][2] = Average_z;
}void refreshCenter(double dataSet[][3]) {       //refresh the old center pointsfor (int i = 0; i < 3; ++i)for (int j = 0; j < dimension; ++j)dataSet[volume + i][j] = dataSet[volume + i + 3][j];
}void show(const int class[], double dataSet[][dimension], int num){        //output the result of the K_meanschar className = '\0';if(num == 0)   className = 'A';else if(num == 1)   className = 'B';else if(num == 2)   className = 'C';for (int i = 0; class[i] != -1; ++i)printf("(%f,%f,%f)->%c\n", dataSet[class[i]][0], dataSet[class[i]][1], dataSet[class[i]][2], className);
}void K_meansAlgo(){double dataSet[volume + 6][dimension];int class_A[volume], class_B[volume], class_C[volume];int lenClass_A = 0, lenClass_B = 0, lenClass_C = 0;//initialize the data set, center points and classinit(dataSet);//refresh the center pointsdouble dist_0, dist_1, dist_2;long int p = 1;                    //Cycle countwhile(1){for (int i = 0; i < volume; ++i) {class_A[i] = -1;class_B[i] = -1;class_C[i] = -1;}lenClass_A = lenClass_B = lenClass_C = 0;//calculate the distance between the point to each center point, then due to the minimum//distance to classify it to witch classfor (int i = 0; i < volume; ++i) {dist_0 = dist(i, volume, dataSet);dist_1 = dist(i, volume + 1, dataSet);dist_2 = dist(i, volume + 2, dataSet);if(minDist(dist_0, dist_1, dist_2) == 0) {class_A[lenClass_A] = i;lenClass_A ++;}else if(minDist(dist_0, dist_1, dist_2) == 1){class_B[lenClass_B] = i;lenClass_B ++;}else if(minDist(dist_0, dist_1, dist_2) == 2){class_C[lenClass_C] = i;lenClass_C ++;}}//calculate the new center pointsnewCenter(class_A, dataSet, 0);     //center point 0newCenter(class_B, dataSet, 1);     //center point 1newCenter(class_C, dataSet, 2);     //center point 2//judge the new center points and the old points weather to meet the conditionsprintf("第%ld轮收敛\n", p++);//Determine whether the new and old center points meet the convergence conditionsif(judge(dataSet) == 0) break;else  refreshCenter(dataSet);     //refresh the old center}//show the resultshow(class_A, dataSet, 0);printf("\n");show(class_B, dataSet, 1);printf("\n");show(class_C, dataSet, 2);printf("\n");}int main() {K_meansAlgo();return 0;
}

五、代码运行结果


程序一共迭代了三次,中心点的移动幅度便满足了我设定的0.0005标准。

六、常见问题及解决

  1. 这年代电脑运行都很快,如果你的数据集也就一百来个数,电脑迭代了100轮都还没结果的时候,注意检查是不是哪里写错了;
  2. 如果一轮迭代后聚类效果不满足要求,这个时候需要将新产生的中心点赋值给旧的中心点,如果没有这一步操作的话迭代将陷入无限循环;
  3. 函数的编写要能被更多的使用者使用,如计算两点距离的函数,那么我们计算中心点到中心点的距离、点到中心点的距离、点到点的距离时都可以引用;
  4. 数据集的大小和数据的维度我一直用的是宏定义,也建议你这么处理,因为可以在后期随时修改数据集大小和维度,提高了程序的灵活性。

K_均值聚类算法(算法设计与C代码实现)相关推荐

  1. Udacity机器人软件工程师课程笔记(二十一) - 对点云进行集群可视化 - 聚类的分割 - K-means|K均值聚类, DBSCAN算法

    聚类的分割 1.K-均值聚类 (1)K-均值聚类介绍 k均值聚类算法(k-means clustering algorithm)是一种迭代求解的聚类分析算法,其步骤是随机选取K个对象作为初始的聚类中心 ...

  2. 模糊聚类的代码实现python_Fuzzy C-Means(模糊C均值聚类)算法原理详解与python实现...

    目录 模糊理论 Fuzzy C-Means算法原理 算法步骤 python实现 参考资料 本文采用数据集为iris,将iris.txt放在程序的同一文件夹下.请先自行下载好. 模糊理论 模糊控制是自动 ...

  3. 机器学习算法之K-means(K均值聚类)算法

    聚类 聚类,简单来说,就是将一个庞杂数据集中具有相似特征的数据自动归类到一起,称为一个簇,簇内的对象越相似,聚类的效果越好.它是一种无监督的学习(Unsupervised Learning)方法,不需 ...

  4. 灰狼算法 c语言 代码,基于灰狼优化的模糊C—均值聚类算法

    谢亮亮+刘建生+朱凡 摘要:针对模糊C-均值聚类算法(FCM)存在易受初始聚类中心影响和容易陷入局部最优的问题,提出了一种将灰狼优化算法(GWO)和模糊C-均值相结合的新聚类算法(GWO-FCM).该 ...

  5. K-Means(K均值聚类算法)

    K-Means(K均值聚类算法) 1.前言 要学习聚类算法就要知道聚类学习算法是什么,为什么要学习聚类学习聚类学习算法,有什么用途,下面就简单的做一下介绍,并且详细的说明k-means均值聚类学习算法 ...

  6. 聚类之K均值聚类和EM算法

    这篇博客整理K均值聚类的内容,包括: 1.K均值聚类的原理: 2.初始类中心的选择和类别数K的确定: 3.K均值聚类和EM算法.高斯混合模型的关系. 一.K均值聚类的原理 K均值聚类(K-means) ...

  7. 机器学习实战-61:K均值聚类算法(K-Means)

    K均值聚类算法(K-Means) 深度学习原理与实践(开源图书)-总目录,建议收藏,告别碎片阅读! 机器学习分为监督学习.无监督学习和半监督学习(强化学习).无监督学习最常应用的场景是聚类(clust ...

  8. 机器学习算法之 K 均值聚类

    机器学习算法之 K 均值聚类 本文我们来学习一下另一种经常听到的机器学习算法-- K 均值聚类. 这个名字确实跟"K 近邻"有些相像,但是要明确的是,"K 近邻" ...

  9. pythonk均值实现_python实现k均值算法示例(k均值聚类算法)

    简易完成平面图的点K平均值剖析,应用欧几里得间距,并且用pylab展现. 编码以下: import pylab as pl #calc Euclid squire def calc_e_squire( ...

最新文章

  1. CentOS 5.1下安装Opensim
  2. jrtplib 打包做了哪些事_30岁前就实现财务自由的人,都做了哪些事
  3. 数据库:后端开发必备的 MySQL日志文件知识点
  4. Sound recording and encoding in MP3 format.
  5. ws flv连接播放得测试代码
  6. python traceback_深入学习Python列表(第一部分)
  7. 记一次golang中sync.Map并发创建、读取的问题
  8. 软件测试的知识点总结
  9. [ASP.NET]NTKO插件使用常见问题
  10. 拓端tecdat|MATLAB用深度学习长短期记忆 (LSTM) 神经网络对智能手机传感器时间序列数据进行分类
  11. Deep Cosine Metric Learning for Person Re-Identification
  12. C语言求解鸡兔同笼问题
  13. 微信小程序 支付宝小程序 实现省市区县四级联动
  14. 名字作诗(藏头名字作诗)
  15. V神的2019和2021
  16. Linux下关于snmp的snmpwalk命令
  17. Expression #3 of ORDER BY clause is not in SELECT list,references column ‘xx‘which is not in SELECT
  18. html文档定一层的标记,HTML基本结构和常用标记.doc
  19. 绿联扩展坞拆解_拆解报告:绿联USB-C多功能拓展坞2A1C
  20. Python sql插入的简便写法

热门文章

  1. 记一次微信小程序源码反解包
  2. 惠州学院计算机基础课程配套练习系统
  3. java trim 空指针_trim()空指针异常问题!
  4. Android 快别用Toast了,来试试Snackbar
  5. 程序设计,就是这样——如何学习程序设计(完整版)
  6. 怎样合理有效的与人争论(讨论)问题?
  7. Java设计模式面试题
  8. FineBI 的多系列折线图
  9. 票据背书以及票据背书的好处
  10. 磁盘类型由动态转换成基本