Shirlies
宁静专注认真的程序媛~

运行环境:Ubuntu+Code::Blocks(G++)

K-均值:在D(数据集)中随机地选择k个对象,每个对象代表一个簇的初始均值或中心。对剩下的每个对象,根据其与各个簇中心的欧式距离,将它分配到最相似的簇中。(不能保证k-均值方法收敛于全局最优解,并且它常常终止于一个局部最优解。可以不同的初始簇中心,多次运行k-均值算法。)

代码为3个簇,初始的簇中心为输入的前三个点。(代码是六七月份写的,直接放上来。)

  1 #include <iostream>
  2 #include <vector>
  3 #include <cmath>
  4 #include <fstream>
  5 #include <cstdlib>
  6 #define OP ','
  7 #define SET_SIZE 3 //簇的个数
  8 
  9 using namespace std;
 10 const double EXP = 1e-6;//用于判断新的中心点与原中心点的距离,如果比exp要小则说明聚类结束
 11 
 12 //定义的点的坐标
 13 typedef struct point
 14 {
 15     double xAxle;
 16     double yAxle;
 17     point()
 18     {
 19         xAxle = 0;
 20         yAxle = 0;
 21     }
 22     point(double _x,double _y)
 23     {
 24         xAxle = _x;
 25         yAxle = _y;
 26     }
 27 }Point;
 28 
 29 //读取文件里面的内容,到numSave数组里面去
 30 void readFile(ifstream &inFile,const string &fileName,vector<Point> &numSave)
 31 {
 32     inFile.clear();
 33 
 34     inFile.open(fileName.c_str());
 35     if(!inFile)
 36     {
 37         cout << "无法打开输入文件!" << endl;
 38     }
 39 
 40     //一行一行的读取
 41     string temp;
 42     while(getline(inFile,temp))
 43     {
 44         //文件里面一行是一个坐标点
 45         double x = atof(temp.substr(0,temp.find(OP)).c_str());
 46         double y = atof(temp.substr(temp.find(OP) + 1,temp.size()-1).c_str());
 47 
 48         numSave.push_back(Point(x,y));
 49     }
 50 
 51     inFile.close();
 52 }
 53 
 54 //计算距离值
 55 double calDistance(Point &a,Point &b)
 56 {
 57     return sqrt((a.xAxle - b.xAxle) * (a.xAxle - b.xAxle) + (a.yAxle - b.yAxle)*(a.yAxle - b.yAxle));
 58 }
 59 
 60 //计算一个簇里面的均值以获得中心点
 61 void calAverage(vector<Point> num,double &xValueAver,double &yValueAver)
 62 {
 63     int xValue = 0,yValue = 0;
 64     for(unsigned int i = 0;i < num.size();i ++)
 65     {
 66         xValue += num[i].xAxle;
 67         yValue += num[i].yAxle;
 68     }
 69 
 70     //获得平均值
 71     xValueAver = (double)xValue/num.size();
 72     yValueAver = (double)yValue/num.size();
 73 
 74 }
 75 
 76 //根据簇中心得到集合,getSetValue存储每一个簇里面的元素
 77 void getSet(vector<Point> &numSave,vector<Point> &setCentre,vector<Point> (&getSetValue)[SET_SIZE])
 78 {
 79 
 80     for(unsigned int i = 0;i < numSave.size();i ++)
 81     {
 82          //设置一个最大值,为了找到最小值
 83         double temp = 100000000.0;
 84         //记录最小的距离numSave[i]的值
 85         unsigned int k = 0;
 86         for(unsigned int j = 0;j < SET_SIZE;j ++)
 87         {
 88             //计算距离
 89             double dis = calDistance(numSave[i],setCentre[j]);
 90             if(temp > dis)
 91             {
 92                 temp = dis;
 93                 k = j;//保留最小距离的那个编号
 94             }
 95         }
 96         //将最小值放在相应编号的簇里面
 97         getSetValue[k].push_back(numSave[i]);
 98     }
 99 }
100 
101 void k_average(vector<Point> &numSave,ofstream &os)
102 {
103     vector<Point> setCentre;
104     vector<Point> getSetValue[SET_SIZE];
105     vector<Point> tempCentre;//用来保存之前的数据,方便对比
106 
107     //初始时将数据的前几个(定义的簇中心个数)作为中心点
108     for(unsigned int i = 0;i < SET_SIZE && i < numSave.size();i ++)
109     {
110         setCentre.push_back(numSave[i]);
111     }
112 
113     while(true)
114     {
115         for(unsigned int i = 0;i < SET_SIZE;i ++)
116         {
117             getSetValue[i].clear();
118         }
119         //根据簇中心找到与簇中心相关的点(距离近的点)
120          getSet(numSave,setCentre,getSetValue);
121 
122          tempCentre = setCentre;
123          bool flag = true;
124          for(unsigned int i = 0;i < SET_SIZE;i ++)
125          {
126              //输出簇中心点
127              os << setCentre[i].xAxle << " and " << setCentre[i].yAxle << endl;
128              /*
129              for(unsigned int j = 0;j < getSetValue[i].size();j ++)
130              {
131                  os << getSetValue[i][j].xAxle << " " << getSetValue[i][j].yAxle << "----";
132              }
133              os << endl;
134              */
135              //根据新的集合获得新的簇中心
136              calAverage(getSetValue[i],setCentre[i].xAxle,setCentre[i].yAxle);
137          }
138 
139          //当其中有一项当前的簇中心相对于之前的移动了较大距离就继续寻找
140          for(unsigned int i = 0;i < SET_SIZE;i ++)
141          {
142              if(fabs(setCentre[i].xAxle - tempCentre[i].xAxle) > EXP || fabs(setCentre[i].yAxle - tempCentre[i].yAxle) > EXP )
143              {
144                  flag = false;
145                  break;
146              }
147          }
148 
149           os << endl;
150           //当每个簇中心不再变化时就不用找了
151          if(flag)
152          {
153              break;
154          }
155 
156     }
157 
158 }
159 
160 int main()
161 {
162     ifstream inFile;
163     vector<Point> numSave;
164     readFile(inFile,"input.txt",numSave);
165 
166     ofstream outFile;
167     outFile.open("output.txt");
168     if(!outFile)
169     {
170         cout << "不能打开文件。请检查文件!" << endl;
171     }
172     k_average(numSave,outFile);
173     return 0;
174 }
代码如下:

 

posted on 2013-08-23 11:10  Shirlies  阅读(981)  评论(0编辑  收藏  举报