当前位置: 首页 > 编程笔记 >

C语言实现K-Means算法

周和安
2023-03-14
本文向大家介绍C语言实现K-Means算法,包括了C语言实现K-Means算法的使用技巧和注意事项,需要的朋友参考一下

一、聚类和聚类算法

聚类,就是将数据对象划分成若干个类,在同一个类中的对象具有较高的相似度,而不同的类相似度较小。聚类算法将数据集合进行划分,分成彼此相互联系的若干类,以此实现对数据的深入分析和数据价值挖掘的初步处理阶段。例如在现代商业领域,聚类分析算法可以从庞大的数据集合中对消费者的消费习惯、消费倾向,以方便决策者制订消费策略。总之,作为数据挖掘中的一个模块,聚类分析算法可以作为一个单独的工具已发现数据库中分布的一些深层信息,并概括出每一类的特点。聚类分析算法也可作为数据挖掘算法中其他分析算法的一个预处理步骤。

在数据挖掘领域,聚类分析算法可以分为一下几个大类,包括划分法、层次法、基于密度的方法、基于网络的方法和基于模型的方法。基于划分的基本思想就是通过迭代的方法将含有N个数据对象的数据集分成K个聚类。具体的步骤就是,用户先给出要划分的个数,然后通过一定的算法反复的进行迭代,使得每次得到的分组比前一次更加接近预期目标,是否优化的判定标准是同组数据之间不同数据之间的相似程度,同组数据相似程度越大,组间似程度越小越优化。

K-means聚类算法的核心思想就是基于对数据集合的划分,它把N个数据对象划分成K个类,使每个类中的数据点到该聚类中心的距离平方和最小。下面我将利用C语言来实现K-means算法,并对该算法在输入不同的聚类个数、改变数据点的密集程度以及初始聚类中心点的选择三个方面来测试该算法。

二、K-means算法实现步骤

通过对聚类和K-Means算法思想的了解,C语言算法的实现过程如下:

(1)通过文件输入N个数据点,并选取其中K(K<N)个数据点作为初始聚类中心;

(2)对剩余的数据点分别计算到各个聚类聚点中心的欧氏距离,并将该点划分到最近的类中;

(3)重新计算各个聚类的聚点中心;

(4)与之前的聚类中心比较,如果聚类中心发生变化,转到(2),否则结束迭并输出结果。

三、K-means算法实现

(一)实现思路

通过以上对K-means算法的了解,该算法主要是通过迭代的思想来求解K个聚类的中心。由于传统数组需要先定义再使用,且在使用的过程中不能实现数组长度的动态增长。同时考虑到设计该算法时,没有涉及到在迭代过程中各个数据点的插入和删除,各个数据点具体划分到那个聚类中,是由结构体成员变量中的className来标识,因此选用了Vector来作为存储数据的容器,这样当从文件输入大量数据时,由程序自己开辟需要的存储空间。同时,也可通过Vector向量容器提供的size和迭代器方法,实现遍历并按照所在聚类进行输出。

每个数据点都含有X、Y坐标,算法初始状态时,指定聚类的具体个数K,初试状态的K个聚类中心由输入文件的前K个数据点来指定。算法在每一次迭代中,需要计算各个点到K个聚类中心坐标的欧氏距离,并选择距离最近的一个聚类,用该聚类的名称标识当前数据点。当所有数据点遍历完后,计算划分到每个聚类中所有数据点X与Y的均值,并将该均值与前一次聚类中心点的坐标相比较。当X与Y的误差小于或者等于1e-6时,则结束迭代并输出收敛后的K歌聚类的中心坐标。

(二)变量和函数说明

(1)定义结构体类型,用于存储数据点坐标、所在聚类、与聚类中心距离

typedef struct point

{

float x,y;    //数据点的坐标
string className; //所属的聚类
float distance;  //距离聚类中心的距离

}Point;

(2)变量声明

vector<Point> dataVector:存储从文件读取的数据

vector<Point> classPoints:存储聚类坐标

vector<Point> &totalPoints):存储所有的数据点

(3)函数声明

字符串转换函数:将整型变量转换成字符串类型:

string converToString(int x);

读入数据函数:从文件读入坐标数据:

vector<Point> readDataFile(string fileName);

初始化数据集合函数:

void initDataset(int classNum,vector<Point> dataVector,vector<Point> &classPoints,vector<Point> &totalPoints);

计算各个数据点距离聚点中心的欧氏距离的函数:

string computerDistance(Point *p_totalPoints,vector<Point> &classPoints);

将各个点划分到相应类的函数:

void kMeansClustering(int classNum,vector<Point> totalPoints,vector<Point> classPoints);

(三)核心代码(部分)

(1)初始化数据集合函数:

void initDataset(int classNum,vector<Point>dataVector,vector<Point>&classPoints, 
         vector<Point>&totalPoints) 
{ 
  int i,j; 
  Point point; 
  for(i=0,j=1; i<dataVector.size(); i++) 
  { 
    if(j<=classNum) //classNum表示聚类的编号 
    { 
      point.x=dataVector[i].x; 
      point.y=dataVector[i].y; 
      point.distance=dataVector[i].distance; 
      point.className=converToString(j);//将整型类型转换成字符串类型 
      classPoints.push_back(point); 
      j++; 
    } 
    point.x=dataVector[i].x; 
    point.y=dataVector[i].y; 
    point.distance=dataVector[i].distance; 
    totalPoints.push_back(point); 
  } 
} 

(2)K-means函数:

void kMeansClustering(int classNum,vector<Point> totalPoints,vector<Point> classPoints) 
{ 
  float tempX=0;//计算聚类中所有数据点X的均值 
  float tempY=0;//计算聚类中所有数据点Y的均值 
  int count=0; //记录每一个类中数据点的数目 
  float errorX=INT_MAX; //假设初始时误差最大 
  float errorY=INT_MAX; 
  vector<Point>::iterator p_totalPoints; 
  vector<Point>::iterator p_classPoints; 
  Point temp; 
  int i; 
  while(errorX > 1e-6 && errorY > 1e-6) 
  { 
    for(p_totalPoints=totalPoints.begin(); p_totalPoints!=totalPoints.end(); p_totalPoints++) 
    { 
      //将所有的点就近分类 
      string className=computerDistance(p_totalPoints,classPoints); 
      (*p_totalPoints).className=className; 
    } 
    errorX=0; 
    errorY=0; 
    //按照均值重新划分聚类中心点 
    for(p_classPoints=classPoints.begin(); p_classPoints!=classPoints.end(); p_classPoints++) 
    { 
      count=0; 
      tempX=0; 
      tempY=0; 
      cout<<"Partition to cluster center "<<p_classPoints->className<<":"; 
      for(p_totalPoints=totalPoints.begin(); p_totalPoints!=totalPoints.end(); p_totalPoints++) 
      { 
        if((*p_totalPoints).className==(*p_classPoints).className) 
        { 
          cout<<" ("<<(*p_totalPoints).x<<","<<(*p_totalPoints).y<<") "; 
          count++; 
          tempX+=(*p_totalPoints).x; 
          tempY+=(*p_totalPoints).y; 
        } 
      } 
      cout<<endl; 
      tempX /=count; 
      tempY /=count; 
      errorX +=fabs(tempX - (*p_classPoints).x); 
      errorY +=fabs(tempY - (*p_classPoints).y); 
      //计算X与Y均值 
      (*p_classPoints).x=tempX; 
      (*p_classPoints).y=tempY; 
    } 
    int i=0; 
    for(p_classPoints=classPoints.begin(); p_classPoints!=classPoints.end(); p_classPoints++,i++) 
    { 
      cout<<"Cluster center "<<i+1<<": x="<<(*p_classPoints).x<<" y="<<(*p_classPoints).y<<endl; 
    } 
    cout<<"-----------------------------------------------------------------"<<endl; 
  } 
  cout<<"Result value convergence"<<endl; 
  i=0; 
  for(p_classPoints=classPoints.begin(); p_classPoints!=classPoints.end(); p_classPoints++,i++) 
  { 
    cout<<"Cluster center "<<i+1<<": x="<<(*p_classPoints).x<<" y="<<(*p_classPoints).y<<endl; 
  } 
  cout<<"-----------------------------------------------------------------"<<endl; 
} 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 本文向大家介绍C语言中K-means算法实现代码,包括了C语言中K-means算法实现代码的使用技巧和注意事项,需要的朋友参考一下 K-means算法是很典型的基于距离的聚类算法,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。 算法过程如下: 1)从N个样本随机选取K个样本作为质心 2)对剩余的每

  • 本文向大家介绍python实现k-means聚类算法,包括了python实现k-means聚类算法的使用技巧和注意事项,需要的朋友参考一下 k-means聚类算法 k-means是发现给定数据集的k个簇的算法,也就是将数据集聚合为k类的算法。 算法过程如下: 1)从N个文档随机选取K个文档作为质心 2)对剩余的每个文档测量其到每个质心的距离,并把它归到最近的质心的类,我们一般取欧几里得距离 3)重

  • 本文向大家介绍k-means 聚类算法与Python实现代码,包括了k-means 聚类算法与Python实现代码的使用技巧和注意事项,需要的朋友参考一下 k-means 聚类算法思想先随机选择k个聚类中心,把集合里的元素与最近的聚类中心聚为一类,得到一次聚类,再把每一个类的均值作为新的聚类中心重新聚类,迭代n次得到最终结果分步解析 一、初始化聚类中心 首先随机选择集合里的一个元素作为第一个聚类中

  • 本文向大家介绍k-means算法流程相关面试题,主要包含被问及k-means算法流程时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 从数据集中随机选择k个聚类样本作为初始的聚类中心,然后计算数据集中每个样本到这k个聚类中心的距离,并将此样本分到距离最小的聚类中心所对应的类中。将所有样本归类后,对于每个类别重新计算每个类别的聚类中心即每个类中所有样本的质心,重复以上操作直到聚类中心不变为止。

  •   本文会介绍一般的k-means算法、k-means++算法以及基于k-means++算法的k-means||算法。在spark ml,已经实现了k-means算法以及k-means||算法。 本文首先会介绍这三个算法的原理,然后在了解原理的基础上分析spark中的实现代码。 1 k-means算法原理分析   k-means算法是聚类分析中使用最广泛的算法之一。它把n个对象根据它们的属性分为k

  • 主要内容:算法应用场景,Sklearn使用K-means算法,总结K-means 聚类算法属于无监督学习,它会将相似的对象归到同一个簇中,该算法原理简单,执行效率高,并且容易实现,是解决聚类问题的经典算法。 尽管如此,任何一款算法都不可能做到完美无瑕,K-measn 算法也有自身的不足之处,比如 K-means 需要通过算术平均数来度量距离,因此数据集的为维度属性必须转换为数值类型,同时 K-means 算法使用随机选择的方式来确定 K 的数量和初始化质心 ,因