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算法实现代码
(0)

相关推荐

  • C语言中K-means算法实现代码

    K-means算法是很典型的基于距离的聚类算法,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大.该算法认为簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标. 算法过程如下: 1)从N个样本随机选取K个样本作为质心 2)对剩余的每个样本测量其到每个质心的距离,并把它归到最近的质心的类 3)重新计算已经得到的各个类的质心 4)迭代2-3步直至新的质心与原质心相等或小于指定阈值,算法结束 #include<stdio.h> #include<stdlib

  • GO语言利用K近邻算法实现小说鉴黄

    Usuage:   go run kNN.go --file="data.txt" 关键是向量点的选择和阈值的判定 样本数据来自国家新闻出版总署发布通知公布的<40部淫秽色情网络小说名单> package main import ( "bufio" "flag" "fmt" "io" "log" "math" "os" "pa

  • k均值算法c++语言实现代码

    复制代码 代码如下: //k-mean.h #ifndef KMEAN_HEAD #define KMEAN_HEAD #include <vector> #include <map> //空间点的定义 class Node {     public:        double pos_x;        double pos_y;        double pos_z;      Node()      {          pos_x = 0.0;          pos

  • R语言实现KMeans聚类算法实例教程

    目录 什么是k-means聚类算法 R 实现kmeans聚类算法 加载包 加载示例数据 寻找最佳聚类数量 使用最优k执行kmeans聚类 kmeans 算法的优缺点 总结 本文和你一起学习无监督机器学习算法 ———— kmeans算法,并在R中给详细的实现示例和步骤. 什么是k-means聚类算法 聚类是从数据集中对观测值进行聚类的机器学习方法.它的目标是聚类相似观测值,不同类别之间差异较大.聚类是一种无监督学习方法,因为它仅尝试从数据集中发现结构,而不是预测应变量的值. 下面是一个市场营销中对

  • C语言实现页面置换算法

    本文实例为大家分享了C语言实现页面置换算法的具体代码,供大家参考,具体内容如下 操作系统实验 页面置换算法(FIFO.LRU.OPT) 概念: 1.最佳置换算法(OPT)(理想置换算法):从主存中移出永远不再需要的页面:如无这样的页面存在,则选择最长时间不需要访问的页面.于所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率. 2.先进先出置换算法(FIFO):是最简单的页面置换算法.这种算法的基本思想是:当需要淘汰一个页面时,总是选择驻留主存时

  • Python 语言实现六大查找算法

    目录 一.顺序查找算法 二.折半查找算法 三.插补查找算法 四.哈希查找算法 五.分块查找算法 六.斐波那契查找算法 七.六种查找算法的时间复杂度 一.顺序查找算法 顺序查找又称为线性查找,是最简单的查找算法.这种算法就是按照数据的顺序一项一项逐个查找,所以不管数据顺序如何,都得从头到尾地遍历一次.顺序查找的优点就是数据在查找前,不需要对其进行任何处理(包括排序).缺点是查找速度慢,如果数据列的第一个数据就是想要查找的数据,则该算法查找速度为最快,只需查找一次即可:如果查找的数据是数据列的最后一

  • C语言实现各种排序算法实例代码(选择,冒泡,插入,归并,希尔,快排,堆排序,计数)

    目录 前言 选择排序 冒泡排序 插入排序 归并排序 希尔排序 快速排序 堆排序 计数排序 总结 前言 平时用惯了高级语言高级工具高级算法,难免对一些基础算法感到生疏.但最基础的排序算法中实则蕴含着相当丰富的优化思维,熟练运用可起到举一反三之功效. 选择排序 选择排序几乎是最无脑的一种排序算法,通过遍历一次数组,选出其中最大(小)的值放在新数组的第一位:再从数组中剩下的数里选出最大(小)的,放到第二位,依次类推. 算法步骤 设数组有n个元素,{ a 0 , a 1 , - , a n } 从数组第

  • C语言实现页面置换算法(FIFO、LRU)

    目录 1.实现效果 2.实现源代码  1.实现效果 2.实现源代码  #include<iostream> #include<process.h> #include<stdlib.h> #include<ctime> #include<conio.h> #include<stdio.h> #include<string.h> using namespace std; #define Myprintf printf(&quo

  • C语言版约瑟夫问题算法实现

    1.问题描述:        有n个人围坐一圈,现从第s个人开始报数,数到m的人出列,接着从出列的下一个人开始重新报数,数到m的人又出列.如此下去,直到所有人都出列为止.试设计确定他们出列次序序列的程序 2.算法步骤:         1.确定存储结构:n个人围成一圈,故使用循环单链表来存储序号         2.算法实现: 该问题共n.m.s三个未知量,所以可以通过三个循环来实现,第一个循环用来确定最开始第一个报数的人的指针位置(单链表的头节点指针指向第s个人),第二个循环用来控制输出序号的

  • C语言 超详细讲解算法的时间复杂度和空间复杂度

    目录 1.前言 1.1 什么是数据结构? 1.2 什么是算法? 2.算法效率 2.1 如何衡量一个算法的好坏 2.2 算法的复杂度 2.3 复杂度在校招中的考察 3.时间复杂度 3.1 时间复杂度的概念 3.2 大O的渐进表示法 3.3 常见时间复杂度计算举例 4.空间复杂度 5. 常见复杂度对比 1.前言 1.1 什么是数据结构? 数据结构(Data Structure)是计算机存储.组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合. 1.2 什么是算法? 算法(Algorit

  • C语言杨氏矩阵查找算法实例讲解

    目录 一.杨氏矩阵介绍 二.查找算法 1.查找思路 2.步骤 3.代码 三.杨氏矩阵例题 代码 特别注意 四.总结 本文以C语言实现,介绍杨氏矩阵中通用的查找算法. 一.杨氏矩阵介绍 杨氏矩阵种,每一行的数都从左到右递增,每一列的数都从上到下递增.如下图是一个简单的杨氏矩阵: 有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在. 要求:时间复杂度小于O(N) 二.查找算法 1.查找思路 杨氏矩阵是很有特点的,它有规律递增的特点决定了针对

随机推荐