码迷,mamicode.com
首页 > 编程语言 > 详细

k_means聚类算法

时间:2021-04-23 11:52:16      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:一个   评分   nbsp   评价   Dimension   namespace   日本   效果图   else   

这是老师上课布置的一道算法题

刚开始理解还是有些困难的

 

查阅一些大佬的博客做出如下理解:

  1.首先你要先确定你要对相关数据分成几类(或者说是几组) —— 先假定为k

  2.再从这些数据中选出 k 个数据(成员)为组长(centroid) —— 为便于理解,下面把数据看成成员  

    >可以随机选择,也可以指定第一个

  3.再遍历每一个成员,判断哪个成员属于哪个组长

    >判断方法:强强联合

      >’实力‘强的分为一组,’实力弱的分为一组‘ (也可以细分多个组,这里只是举列k = 2)

  4.分完组后,再寻找新的组长,但是这个组长并不在成员中寻找,可以理解为再造一个成员当组长

    >寻找方法:取均值

      >假如每个成员的 ’强弱‘ 根据 语 数 英 三门成绩来决定

      >那么该组的新组长的语数英成绩就是该组 语数英 的平均成绩

      >这就是一个三维的比较

      >像如果单纯比身高的话就是一维的比较

  5.然后只需要重复循环 n 次(自己随便定)就可以达到聚类的效果了

    >n的大小要根据不同情况来调节,来达到更好的聚类效果

 

下面就来看看老师给的ppt上面讲了些啥子吧:—— 有些复制不上来的我就先翻译一下吧

  1.部分概念

  K-means算法是很典型的基于距离的聚类算法,采用距离作为相似性的评价指标(还有按比例 --- 正余弦好像),即认为两个对象的距离越近,其相似度就越大。

  该算法认为类是有距离靠近的对象组成的,因此把得到紧凑且独立的类作为最终目标

  

 

   2.举例

   技术图片

 

   技术图片

 

 这表达式看不懂呢就随便猜猜是干嘛的就行,影响不大

  技术图片

 

 

我就不解释了,老师给的ppt我也没怎么看,我就照搬下来了

技术图片 

 技术图片

 -------------------------------------------------------------------------------------------------------

技术图片

 

 

-----------------------------------------------------------

技术图片

 

技术图片

技术图片

 

 效果图变化过程:

技术图片

 

最后给上我的代码和修改老师的源代码

  1 /*K-Means*/
  2 //#include "stdafx.h"
  3 #include<iostream>
  4 #include<cmath>
  5 #include<vector>
  6 #include<ctime>
  7 #include<cstdlib>
  8 using namespace std;
  9 typedef unsigned int uint;
 10 
 11 class Cluster
 12 {
 13 public:
 14 
 15     vector<double> centroid;
 16     vector<uint> samples;
 17 };
 18 double cal_distance(vector<double> a, vector<double> b)//计算距离 
 19 {
 20     uint da = a.size();
 21     uint db = b.size();
 22     if (da != db) //cerr << "Dimensions of two vectors must be same!!\n";
 23     {
 24         cout<<"ERROR"<<endl;
 25         return 0; 
 26     }
 27     double val = 0.0;
 28     for (uint i = 0; i < da; i++)
 29     {
 30         val += pow((a[i] - b[i]), 2);
 31     }
 32     return pow(val, 0.5);
 33 }
 34 vector<Cluster> k_means(vector<vector<double> > trainX, uint k, uint maxepoches)
 35 {
 36     const uint row_num = trainX.size(); // 训练的样本大小 
 37     const uint col_num = trainX[0].size(); // 维度 
 38 
 39     /*初始化聚类中心*/
 40     vector<Cluster> clusters(k);
 41     uint seed = (uint)time(NULL); 
 42     
 43     for (uint i = 0; i < k; i++)
 44     {
 45         srand(seed);
 46         int c = rand() % row_num;
 47         clusters[i].centroid = trainX[c];
 48         seed = rand();
 49     }
 50     /*多次迭代直至收敛,本次试验迭代100次*/
 51     for (uint it = 0; it < maxepoches; it++)
 52     {
 53         /*每一次重新计算样本点所属类别之前,清空原来样本点信息*/
 54         for (uint i = 0; i < k; i++)
 55         {
 56             clusters[i].samples.clear();
 57         }
 58         /*求出每个样本点距应该属于哪一个聚类*/
 59         for (uint j = 0; j < row_num; j++)
 60         {
 61             /*都初始化属于第0个聚类*/
 62             uint c = 0;
 63             double min_distance = cal_distance(trainX[j], clusters[c].centroid); // 寻找距离最小的 
 64             for (uint i = 1; i < k; i++)
 65             {
 66                 double distance = cal_distance(trainX[j], clusters[i].centroid);
 67                 if (distance < min_distance)
 68                 {
 69                     min_distance = distance;
 70                     c = i;
 71                 }
 72             }
 73             clusters[c].samples.push_back(j);
 74         }
 75 
 76         /*更新聚类中心*/
 77         for (uint i = 0; i < k; i++)
 78         {
 79             vector<double> val(col_num, 0.0); // 新组长 
 80             for (uint j = 0; j < clusters[i].samples.size(); j++)
 81             {
 82                 uint sample = clusters[i].samples[j]; // i组j小弟 
 83                 for (uint d = 0; d < col_num; d++)
 84                 {
 85                     val[d] += trainX[sample][d];
 86                     if (j == clusters[i].samples.size() - 1)
 87                         clusters[i].centroid[d] = val[d] / clusters[i].samples.size();
 88                 }
 89             }
 90         }
 91     }
 92     return clusters;
 93 }
 94 
 95 int main()
 96 {
 97     vector<vector<double> > trainX(9, vector<double>(1, 0));
 98     //对9个数据{1 2 3 11 12 13 21 22 23}聚类
 99     double data = 1.0;
100     uint kk = 2;
101     for (uint i = 0; i < 9; i++)
102     {
103         trainX[i][0] = data;
104         if ((i + 1) % kk == 0) data += 8;
105         else data++;
106     }
107 
108     /*k-means聚类*/
109     vector<Cluster> clusters_out = k_means(trainX, kk, 100);
110     cout << "***********" << kk << endl;
111 
112     /*输出分类结果*/
113     for (uint i = 0; i < clusters_out.size(); i++)
114     {
115         cout << "Cluster " << i << " :" << endl;
116 
117         /*子类中心*/
118         cout << "\t" << "Centroid: " << "\n\t\t[ ";
119         for (uint j = 0; j < clusters_out[i].centroid.size(); j++)
120         {
121             cout << clusters_out[i].centroid[j] << " ";
122         }
123         cout << "]" << endl;
124 
125         /*子类样本点*/
126         cout << "\t" << "Samples:\n";
127         for (uint k = 0; k < clusters_out[i].samples.size(); k++)
128         {
129             uint c = clusters_out[i].samples[k];
130             cout << "\t\t[ ";
131             for (uint m = 0; m < trainX[0].size(); m++)
132             {
133                 cout << trainX[c][m] << " ";
134             }
135             cout << "]\n";
136         }
137     }
138     return 0;
139 }

 

老师给的是一维的,

 

技术图片

这个表格是要聚类的三维数据

 

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <cstdlib>
  5 #include <vector>
  6 #include <ctime>
  7 using namespace std;
  8 class Country{
  9     public:
 10         Country &operator=(Country c)
 11         {
 12             this->Paim = c.Paim;
 13             this->m_Name = c.m_Name;
 14             return *this;
 15         }
 16         string m_Name;
 17         vector<int>Paim;    
 18 };
 19 class Cluster{
 20     public:
 21         Country Centroid;
 22         vector<int>Samples;
 23 };
 24 
 25 double cal_(Country a,Country b)
 26 {
 27     int la = a.Paim.size();
 28     int lb = b.Paim.size();
 29     
 30     if(la != lb)
 31     {
 32         cout<<"ERROR"<<endl;
 33         return 0;
 34     }
 35     
 36     double val = 0.0;
 37     for(int i = 0;i < la;i++)
 38     {
 39         val += pow((a.Paim[i] - b.Paim[i]),2);
 40     }
 41     
 42     return pow(val,0.5);
 43 }
 44 
 45 vector<Cluster> k_means(vector<Country>TrainX,int k,int train_num)
 46 {
 47     vector<Cluster>Clu(k);
 48     const int row_num = TrainX.size(); // 计算有多少国家 
 49     const int col_num = TrainX[0].Paim.size(); // 计算有多少个评分标准
 50     
 51     //初始化 
 52     int seed = (unsigned)time(NULL);
 53     for(int i = 0;i < k;i++)
 54     {
 55         srand(seed);
 56         int c = rand() % row_num;
 57         Clu[i].Centroid = TrainX[c];
 58         seed = rand();    
 59     } 
 60     
 61     for(int t = 0;t < train_num;t++) // 训练次数 
 62     {
 63         //清空小弟
 64         for(int i = 0;i < k;i++)
 65         {
 66             Clu[i].Samples.clear();
 67         }
 68         for(int it = 0;it < row_num;it++) // 给每组的组长分配组员 
 69         {
 70             int c = 0;
 71             double min_d = cal_(Clu[c].Centroid,TrainX[it]); // 先默认该成员是属于第一组 
 72             for(int i = 1;i < k;i++) // 寻找到底属于哪一组 
 73             {
 74                  double dist = cal_(Clu[i].Centroid,TrainX[it]);
 75                  if(min_d > dist)
 76                  {
 77                      min_d = dist;
 78                      c = i;
 79                  }
 80             }
 81             Clu[c].Samples.push_back(it); 
 82         }
 83         
 84         
 85         //分配完了再重新选择组长 —— 虚拟组长 
 86         for(int i = 0;i < k;i++) // k组 
 87         {
 88             int s = Clu[i].Samples.size(); // 该组有多少个组员 
 89             Country val;
 90             for(int j = 0;j < col_num;j++)
 91             {
 92                 val.Paim.push_back(0);
 93             }
 94             for(int j = 0;j < s;j++)
 95             {
 96                 for(int l = 0;l < col_num;l++) // 维度 
 97                 {
 98                     val.Paim[l] += TrainX[Clu[i].Samples[j]].Paim[l] / s;    
 99                 }    
100             }
101             Clu[i].Centroid = val;    
102         } 
103     }
104     return Clu;
105 }
106 int main()
107 {
108     vector<Country>C;
109     int n = 12; //就实验12个数据吧 数据太多不想打了
110     Country c[n];
111     
112     c[0].m_Name = "中国";
113     c[0].Paim.push_back(73); 
114     c[0].Paim.push_back(40); 
115     c[0].Paim.push_back(7); 
116     
117     c[1].m_Name = "日本";
118     c[1].Paim.push_back(60); 
119     c[1].Paim.push_back(15); 
120     c[1].Paim.push_back(5); 
121 
122     c[2].m_Name = "韩国";
123     c[2].Paim.push_back(61); 
124     c[2].Paim.push_back(19); 
125     c[2].Paim.push_back(2);
126     
127     c[3].m_Name = "伊朗";
128     c[3].Paim.push_back(34); 
129     c[3].Paim.push_back(18); 
130     c[3].Paim.push_back(6);
131     
132     c[4].m_Name = "沙特";
133     c[4].Paim.push_back(67); 
134     c[4].Paim.push_back(26); 
135     c[4].Paim.push_back(10);
136     
137     c[5].m_Name = "伊拉克";
138     c[5].Paim.push_back(91); 
139     c[5].Paim.push_back(40); 
140     c[5].Paim.push_back(4);
141     
142     c[6].m_Name = "卡塔尔";
143     c[6].Paim.push_back(101); 
144     c[6].Paim.push_back(40); 
145     c[6].Paim.push_back(13);
146     
147     c[7].m_Name = "阿联酋";
148     c[7].Paim.push_back(81); 
149     c[7].Paim.push_back(40); 
150     c[7].Paim.push_back(6);
151     
152     c[8].m_Name = "乌兹别克斯坦";
153     c[8].Paim.push_back(88); 
154     c[8].Paim.push_back(40); 
155     c[8].Paim.push_back(8);
156     
157     c[9].m_Name = "泰国";
158     c[9].Paim.push_back(122); 
159     c[9].Paim.push_back(40); 
160     c[9].Paim.push_back(17);
161     
162     c[10].m_Name = "越南";
163     c[10].Paim.push_back(102); 
164     c[10].Paim.push_back(50); 
165     c[10].Paim.push_back(17);
166     
167     c[11].m_Name = "阿曼";
168     c[11].Paim.push_back(87); 
169     c[11].Paim.push_back(50); 
170     c[11].Paim.push_back(12);
171     
172     for(int i = 0;i < n;i++)
173     {
174         C.push_back(c[i]);
175     }
176     int kk = 2;
177     vector<Cluster> clusters_out = k_means(C, kk,100);
178     
179     for(int i = 0;i < clusters_out.size();i++)
180     {
181         
182     }
183     cout << "***********" << kk << endl;
184 
185     /*输出分类结果*/
186     for (int i = 0; i < clusters_out.size(); i++)
187     {
188         cout << "Cluster " << i << " :" << endl;
189 
190         /*子类中心*/
191         cout << "\t" << "Centroid: " << "\n\t\t[ ";
192         for (int j = 0; j < clusters_out[i].Centroid.Paim.size(); j++)
193         {
194             cout << clusters_out[i].Centroid.Paim[j] << " ";
195         }
196         cout << "]" << endl;
197 
198         /*子类样本点*/
199         cout << "\t" << "Samples:\n";
200         for (int k = 0; k < clusters_out[i].Samples.size(); k++)
201         {
202             int c = clusters_out[i].Samples[k];
203             cout << "\t\t[ ";
204             cout<<C[c].m_Name<<"\t";
205             for (int m = 0; m < C[0].Paim.size(); m++)
206             {
207                 cout << C[c].Paim[m] << " ";
208             }
209             cout << "]\n";
210         }
211     }
212     return 0;
213 }

就先这样吧

再把输出给一下吧’

技术图片

----------------------------------

技术图片

k_means聚类算法

标签:一个   评分   nbsp   评价   Dimension   namespace   日本   效果图   else   

原文地址:https://www.cnblogs.com/Alan-Wangyoubiao/p/14689070.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!