无监督学习算法K-means算法总结与c++编程实现

来源:互联网 发布:罗其胜网络班教程 编辑:程序博客网 时间:2024/06/08 14:12




Figure 1: K-means algorithm. Training examples are shown as dots, and cluster centroids are shown as crosses. (a) Original dataset. (b) Random initial cluster centroids (in this instance, not chosen to be equal to twotrainingexamples). (c-f) Illustration of running two iterations of k-means. In each iteration, we assign each training example to the closest cluster centroid(shown by “painting” the training examples the same color as the cluster centroid to which is assigned); then we move each cluster centroid to the mean of the points assigned to it. (Best viewed in color.) Images courtesy Michael Jordan.

注意:

问题1:K值选取问题

K的选取通常是我们的目标,也就是说,我们要将这队数据分为几类。因此,是相对明确的。

问题2:初始值的选取问题

初始值的选取对于迭代的结果有较大的影响,选取不当,会出现所有点都归为一类的情况。一个通常的解决方案是:随机选取多组初始值进行分类,选取损失函数最小的分类结果。

编程举例:

将如下三维空间的点进行k-means分类:

[input.txt]

1.0 , 5.7 , 2.8

4.5 , 5.2 , -0.3

-0.9 , 8.1 , 1.4

0.5 , 6.6 , 2.3

3.5 , 4.7 , 0.2

4.7 , 5.9 , -1

5.1 , 8.2 , 0.9

2.1 , 7.4 , 3.0

0.6 , 6.5 , 3.8

在三维空间的图及k-means分类的结果


K-means算法的c++实现代码:

#include <iostream>#include <fstream>#include <cmath>#include <vector>#define dim  3//输入特征x的维数#define K    2//分类的个数#define MAX_NUM 100//读取输入数据的最大数目using namespace std;//定义类,封装输入向量x,及它要分到哪个类别class InputFeature{public:double x[dim];//保存输入数据的向量坐标int cluster;//标志分类的哪一类(0,1,...,K)InputFeature(double x[dim])//构造函数{       memcpy(this->x,x,sizeof(double)*dim);   cluster=-1;}//输入函数void print(){cout<<"cluster="<<cluster<<"   x=[";for (int i=0;i<dim;i++){cout<<x[i]<<" ";}cout<<"]"<<endl;}//计算该特征向量与输入向量的2范数(欧式距离)double distanceOf(double u[dim]){        double distance=0;for (int i=0;i<dim;i++){distance+=(u[i]-x[i])*(u[i]-x[i]);}distance=sqrt(distance);return distance;}};vector<InputFeature> InputVector;//保存输入特征向量void inputData()//从文件中读取数据{ifstream ifile("input.txt");      if(!ifile)      {          cout<<"input.txt cannot be opened!"<<endl;          return;      }    char ch;      int i;    for (i=0;i<MAX_NUM;i++)//读取数目      {  string s_X1,s_X2,s_X3;        if(!ifile.get(ch))          {            return;          }          while (ch!=',')//读取第一个数据        {              if (ch==' ')//跳过空格              {  if(!ifile.get(ch))  {return;  }                continue;              }            s_X1+=ch; if(!ifile.get(ch))  {return;  }          }  if(!ifile.get(ch))          {            return;          }        while (ch!=',')//读取第二个数据         {              if (ch==' ')              {  if(!ifile.get(ch))  {return;  }  //跳过空格                  continue;              }              s_X2+=ch;  if(!ifile.get(ch))  {return;  }           }  if(!ifile.get(ch))          {            return;          }         while(ch!='\n')//读取第三个数据         {              if (ch==' ')              {  if(!ifile.get(ch))  {return;  }                    continue;              }              s_X3+=ch;  if(!ifile.get(ch))  {cout<<"文件已经读完!"<<endl;  return;  }           }double xt[dim];//将读入的字符串转化为小数xt[0]=atof(s_X1.c_str());xt[1]=atof(s_X2.c_str());xt[2]=atof(s_X3.c_str());InputFeature t1(xt);//生成特征向量    InputVector.push_back(t1);//保存到数组    }      ifile.close();}//计算在误差err内,2次迭代的结果是否一样bool CompareU(double U0[K][dim],double U[K][dim],double err){for (int k=0;k<K;k++){for (int d=0;d<dim;d++){if(abs(U0[k][d]-U[k][d])>err){return false;}}   }return true;}//k-means算法核心void k_means(double U[K][dim]){   double U0[K][dim];   memcpy(U0,U,sizeof(double)*K*dim);   while (true)   {   //第一步 标定集合中的点,离哪个U点最近,即将其cluster修改为对应的分类   int j;   vector<InputFeature>::iterator it;   for(it = InputVector.begin(); it != InputVector.end(); ++it)   {   double dist[K];   for (j=0;j<K;j++)//计算该向量到各个标定向量的欧式距离   {   dist[j]=it->distanceOf(U[j]);   }   double minDist=dist[0];//初始化最小距离   it->cluster=0;//初始化分类   for (j=1;j<K;j++)   {   if (dist[j]<minDist)//如果发现离第j个更近,则更新分类   {   minDist=dist[j];   it->cluster=j;   }   }   }   //第二步 更新重心U   double sum[K][dim],num[K];   memset(&sum,0,sizeof(double)*K*dim);   memset(&num,0,sizeof(double)*K);       for(it = InputVector.begin(); it != InputVector.end(); ++it)   {   for (int d=0;d<dim;d++)//计算所有相同分类的坐标重心   {   sum[it->cluster][d]+=it->x[d];   }   num[it->cluster]++;//计算相同分类的数目   }   for (j=0;j<K;j++)//更新标定向量的重心   {   for (int d=0;d<dim;d++)   {   if (num[j]!=0)     U[j][d]=(sum[j][d])/(num[j]);   }   }   //判断是否收敛, U==U0时收敛   if (CompareU(U0,U,1.0e-5))   {   break;   }   memcpy(U0,U,sizeof(double)*K*dim);//将本次迭代的结果保存   }   //输出聚类的结果   cout<<"k-means聚类的中心点坐标为:"<<endl;   for (int k=0;k<K;k++)   {   cout<<"U"<<k<<"=";   for (int d=0;d<dim;d++)   {   cout<<U[k][d]<<" ";   }   cout<<endl;   }   //此时每个元素的分类情况为:   cout<<"输入向量的聚类情况及坐标点:"<<endl;   vector<InputFeature>::iterator it;   for(it = InputVector.begin(); it != InputVector.end(); ++it)   {   it->print();   }   //计算误差函数   double J=0;   for(it = InputVector.begin(); it != InputVector.end(); ++it)   {   J+=it->distanceOf(U[it->cluster]);   }   cout<<"误差函数J(c,u)="<<J<<endl;}/* *@author:郑海波 zhb931706659@126.com *http://blog.csdn.net/nuptboyzhb/ */int main(){cout<<"@author:郑海波 zhb931706659@126.com"<<endl;inputData();//读入输入的数据//初始化K=2个标定向量double U[K][dim]={{4.5,8.1,2.8},{-0.9,4.7,-0.3}};k_means(U);//进行k-means聚类return 0;}

实验结果:


matlab plot code

% *@author:郑海波 zhb931706659@126.com% *http://blog.csdn.net/nuptboyzhb/clear all;clc;close all;x=[1.0 , 5.7 , 2.84.5 , 5.2 , -0.3-0.9 , 8.1 , 1.40.5 , 6.6 , 2.33.5 , 4.7 , 0.24.7 , 5.9 , -15.1 , 6.2 , 0.92.1 , 7.4 , 3.0];subplot(1,2,1);plot3(x(:,1),x(:,2),x(:,3),'o');hold on;U1=[4.5,8.1,2.8];U2=[-0.9,4.7,-0.3];plot3(U1(1),U1(2),U1(3),'+');hold on;plot3(U2(1),U2(2),U2(3),'r+');hold on;title('o--原始数据,+初始的迭代点');x1=[1.0 , 5.7 , 2.8-0.9 , 8.1 , 1.40.5 , 6.6 , 2.32.1 , 7.4 , 3.0];x2=[4.5 , 5.2 , -0.33.5 , 4.7 , 0.24.7 , 5.9 , -15.1 , 6.2 , 0.9];subplot(1,2,2);plot3(x1(:,1),x1(:,2),x1(:,3),'o');hold on;plot3(x2(:,1),x2(:,2),x2(:,3),'ro');hold on;U1=[4.45 5.5 -0.05];U2=[0.675 6.95 2.125];plot3(U1(1),U1(2),U1(3),'r*');hold on;plot3(U2(1),U2(2),U2(3),'*');hold on;title('迭代结果,*为聚类点的中心');

未经允许不得用于商业目的




原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孩子声调不会标怎么办 孩子拼音发音不准怎么办 孩子学拼音不会怎么办? 孩子不会拼生字怎么办? 对数字不敏感怎么办 孩子说话不算数怎么办 儿童做事不认真怎么办 幼儿园小朋友爱打人怎么办 遇到熊孩子家长怎么办 小孩嘴烂了怎么办 孩子杯宠坏了怎么办 小孩子老爱打人怎么办 小孩偏执的性格怎么办 孩子上学爱打人怎么办 宝宝爱动手打人怎么办 幼儿爱打人教师怎么办 中班幼儿爱打人怎么办 幼儿园小班小朋友打人老师怎么办 2岁小朋友打人怎么办 幼儿爱乱讲话怎么办 幼儿园小孩打架老师怎么办 宝宝不自信胆小怎么办 小孩不尊重父母怎么办 孩子有洁癖应该怎么办 宝宝攻击性太弱怎么办 小孩在幼儿园打人怎么办 小孩说老师打人怎么办 孩子总动手打人怎么办 辅导小孩老发火怎么办 孩子喜欢咬人怎么办 小孩见家人不叫怎么办 孩子识字量差怎么办 小孩子字写不好怎么办 宝宝不好好写字怎么办 学拉丁有反应怎么办 苏泊尔水壶坏了怎么办 dell笔记本很卡怎么办 cad运行很慢怎么办 wacom买完了然后怎么办 手绘板装完驱动后怎么办 数位板没屏幕怎么办