kmean均值算法是一种最常见的聚类算法。算法实现简单,效果也比较好。kmean算法把n个对象划分成指定的k个簇,每个簇中所有对象的均值的平均值为该簇的聚点(中心)。

k均值算法有如下五个步骤:

  1. 随机生成最初始k个簇心。可以从样本中随机选择,也可以根据样本中每个特征的取值特点随机生成。
  2. 对每个样本计算到每个簇心的欧式距离,将样本划分到欧氏距离最小的簇心(聚点)。
  3. 对划分到同一个簇心(聚点)的样本计算平均值,用均值更新簇心(聚点)
  4. 若某些簇心(聚点)发生变化,转到2;若所有的聚点都没有变化,转5
  5. 输出划分结果
  1. #include <vector>
  2. #include <cassert>
  3. #include <iostream>
  4. #include <cmath>
  5. #include <fstream>
  6. #include <climits>
  7. #include <ctime>
  8. #include <iomanip>
  9.  
  10. using namespace std;
  11. namespace terse {
  12. class Kmeans {
  13. private:
  14. vector<vector<double>> m_dataSet;
  15. int m_k;
  16. vector<int> m_clusterResult; // result of cluster
  17. vector<vector<double>> m_cluserCent; //center of k clusters
  18.  
  19. private:
  20. vector<string> split(const string& s, string pattern) {
  21. vector<string> res;
  22. size_t start = ;
  23. size_t end = ;
  24. while (start < s.size()) {
  25. end = s.find_first_of(pattern, start);
  26. if (end == string::npos) {
  27. res.push_back(s.substr(start, end - start - ));
  28. return res;
  29. }
  30. res.push_back(s.substr(start, end - start));
  31. start = end + ;
  32. }
  33. return res;
  34. }
  35.  
  36. void loadDataSet(const char* fileName) {
  37. ifstream dataFile(fileName);
  38. if (!dataFile.is_open()) {
  39. cerr << "open file " << fileName << "failed!\n";
  40. return;
  41. }
  42. string tmpstr;
  43. vector<double> data;
  44. while (!dataFile.eof()) {
  45. data.clear();
  46. tmpstr.clear();
  47. getline(dataFile, tmpstr);
  48. vector<string> tmp = split(tmpstr, ",");
  49. for (string str : tmp) {
  50. data.push_back(stod(str));
  51. }
  52. this->m_dataSet.push_back(data);
  53. }
  54. dataFile.close();
  55. }
  56.  
  57. //compute Euclidean distance of two vector
  58. double distEclud(vector<double>& v1, vector<double>& v2) {
  59. assert(v1.size() == v2.size());
  60. double dist = ;
  61. for (size_t i = ; i < v1.size(); i++) {
  62. dist += (v1[i] - v2[i]) * (v1[i] - v2[i]);
  63. }
  64. return sqrt(dist);
  65. }
  66.  
  67. void generateRandCent() {
  68. int numOfFeats = this->m_dataSet[].size();
  69. size_t numOfSamples = this->m_dataSet.size();
  70.  
  71. //first:min second:max
  72. vector<pair<double, double>> minMaxOfFeat(numOfFeats);
  73. for (int i = ; i < numOfFeats; i++) {
  74. minMaxOfFeat[i].first = this->m_dataSet[][i];
  75. minMaxOfFeat[i].second = this->m_dataSet[][i];
  76. }
  77. for (size_t i = ; i < numOfSamples; i++) {
  78. for (int j = ; j < numOfFeats; j++) {
  79. if (this->m_dataSet[i][j] > minMaxOfFeat[j].second) {
  80. minMaxOfFeat[j].second = this->m_dataSet[i][j];
  81. }
  82. if (this->m_dataSet[i][j] < minMaxOfFeat[j].first) {
  83. minMaxOfFeat[j].first = this->m_dataSet[i][j];
  84. }
  85. }
  86. }
  87. srand(time(NULL));
  88. for (int i = ; i < this->m_k; i++) {
  89. for (int j = ; j < numOfFeats; j++) {
  90. this->m_cluserCent[i][j] = minMaxOfFeat[j].first
  91. + (minMaxOfFeat[j].second - minMaxOfFeat[j].first)
  92. * (rand() / (double) RAND_MAX);
  93. }
  94. }
  95.  
  96. }
  97.  
  98. void printClusterCent(int iter) {
  99. int m = this->m_cluserCent.size();
  100. int n = this->m_cluserCent[].size();
  101. cout << "iter = " << iter;
  102. for (int i = ; i < m; i++) {
  103. cout << " {";
  104. for (int j = ; j < n; j++) {
  105. cout << this->m_cluserCent[i][j] << ",";
  106. }
  107. cout << "};";
  108. }
  109. cout << endl;
  110. }
  111.  
  112. void writeResult(const char* fileName = "res.txt") {
  113. ofstream fout(fileName);
  114. if (!fout.is_open()) {
  115. cerr << "open file " << fileName << "failed!";
  116. return;
  117. }
  118. for (size_t i = ; i < this->m_dataSet.size(); i++) {
  119. for (size_t j = ; j < this->m_dataSet[].size(); j++) {
  120. fout << this->m_dataSet[i][j] << "\t";
  121. }
  122. fout << setprecision() << this->m_clusterResult[i] << "\n";
  123. }
  124. fout.close();
  125. }
  126.  
  127. public:
  128. Kmeans(int k, const char* fileName) {
  129. this->m_k = k;
  130. this->loadDataSet(fileName);
  131. this->m_clusterResult.reserve(this->m_dataSet.size());
  132. this->m_cluserCent = vector<vector<double>>(k,
  133. vector<double>(this->m_dataSet[].size()));
  134. generateRandCent();
  135. }
  136.  
  137. Kmeans(int k, vector<vector<double>>& data) {
  138. this->m_k = k;
  139. this->m_dataSet = data;
  140. this->m_clusterResult.reserve(this->m_dataSet.size());
  141. this->m_cluserCent = vector<vector<double>>(k,
  142. vector<double>(this->m_dataSet[].size()));
  143. generateRandCent();
  144. }
  145.  
  146. //verbose = 1,printClusterCent();
  147. void kmeansCluster(int verbose = ) {
  148. int iter = ;
  149. bool isClusterChanged = true;
  150. while (isClusterChanged) {
  151. isClusterChanged = false;
  152. //step 1: find the nearest centroid of each point
  153. int numOfFeats = this->m_dataSet[].size();
  154. size_t numOfSamples = this->m_dataSet.size();
  155. for (size_t i = ; i < numOfSamples; i++) {
  156. int minIndex = -;
  157. double minDist = INT_MAX;
  158. for (int j = ; j < this->m_k; j++) {
  159. double dist = distEclud(this->m_cluserCent[j],
  160. m_dataSet[i]);
  161. if (dist < minDist) {
  162. minDist = dist;
  163. minIndex = j;
  164. }
  165. }
  166. if (m_clusterResult[i] != minIndex) {
  167. isClusterChanged = true;
  168. m_clusterResult[i] = minIndex;
  169. }
  170. }
  171.  
  172. //step 2: update cluster center
  173. vector<size_t> cnt(this->m_k, );
  174. this->m_cluserCent = vector<vector<double>>(this->m_k,
  175. vector<double>(numOfFeats, 0.0));
  176. for (size_t i = ; i < numOfSamples; i++) {
  177. for (int j = ; j < numOfFeats; j++) {
  178. this->m_cluserCent[this->m_clusterResult[i]][j] +=
  179. this->m_dataSet[i][j];
  180. }
  181. cnt[this->m_clusterResult[i]]++;
  182. }
  183. // mean of the vector belong to a cluster
  184. for (int i = ; i < this->m_k; i++) {
  185. for (int j = ; j < numOfFeats; j++) {
  186. this->m_cluserCent[i][j] /= cnt[i];
  187. }
  188. }
  189. if (verbose)
  190. printClusterCent(iter++);
  191. }
  192. writeResult();
  193. }
  194. };
  195.  
  196. };
  197.  
  198. int main(){
  199. terse::Kmeans kmeans(,"datafile.txt");
  200. kmeans.kmeansCluster();
  201. return ;
  202. }
  203. /*namespace terse*/

kmean算法C++实现的更多相关文章

  1. <转>与EM相关的两个算法-K-mean算法以及混合高斯模型

    转自http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006924.html http://www.cnblogs.com/jerrylead/ ...

  2. EM相关两个算法 k-mean算法和混合高斯模型

    转自http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006924.html http://www.cnblogs.com/jerrylead/ ...

  3. 机器学习课程-第8周-聚类(Clustering)—K-Mean算法

    1. 聚类(Clustering) 1.1 无监督学习: 简介 在一个典型的监督学习中,我们有一个有标签的训练集,我们的目标是找到能够区分正样本和负样本的决策边界,在这里的监督学习中,我们有一系列标签 ...

  4. K-Means聚类算法原理

    K-Means算法是无监督的聚类算法,它实现起来比较简单,聚类效果也不错,因此应用很广泛.K-Means算法有大量的变体,本文就从最传统的K-Means算法讲起,在其基础上讲述K-Means的优化变体 ...

  5. 学习OpenCV——Kmean(C++)

    从前也练习使用过OpenCV的Kmean算法,但是那版本低,而且也是基于C的开发.这两天由于造论文的需要把它重新翻出来在研究一下C++,发现有了些改进 kmeans C++: doublekmeans ...

  6. 运用三角不等式加速Kmeans聚类算法

    运用三角不等式加速Kmeans聚类算法 引言:最近在刷<数据挖掘导论>,第九章, 9.5.1小节有提到,可以用三角不等式,减少不必要的距离计算,从而达到加速聚类算法的目的.这在超大数据量的 ...

  7. MLlib--PIC算法

    转载请标明出处http://www.cnblogs.com/haozhengfei/p/82c3ef86303321055eb10f7e100eb84b.html PIC算法   幂迭代聚类     ...

  8. ML: 聚类算法-K均值聚类

    基于划分方法聚类算法R包: K-均值聚类(K-means)                   stats::kmeans().fpc::kmeansruns() K-中心点聚类(K-Medoids) ...

  9. K-SVD算法

    它与K-mean算法原理上是类似的: K-mean 算法: (之前写过:http://www.cnblogs.com/yinheyi/p/6132362.html) 对于初始化的类别中心,可以看作初化 ...

随机推荐

  1. PHP环境的搭建及与nginx的集成

    1.  去php官网下载最新稳定版(最新其实是7.0,为了兼容性,使用5.6.16) wget http://cn2.php.net/get/php-5.6.16.tar.gz/from/this/m ...

  2. 关于java的volatile关键字与线程栈的内容以及单例的DCL

    用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最新的值.volatile很容易被误用,用来进行原子性操作. package com.guangshan.test; pub ...

  3. Android-ActionBar-与Menu结合

    ActionBar就是一个标题栏,以前Android3.0之前还称为标题栏,Android3.0之后取名为ActionBar 首先必须在AndroidManifest.xml中指定Applicatio ...

  4. MVC-1.1 BundleConfig-ScriptBundle

    App_Start中的BudleCnfig.cs中 bundles.Add(new ScriptBundle("~/bundles/jquery").Include( " ...

  5. html隐藏元素

    <body> <div>display:元素的位置不被占用</div> <div id="div1" style="displa ...

  6. XPath高级用法(冰山一角)

    运算符+内置函数 使用XPath选择元素时,使用运算符+内置函数来进行筛选: .//div[contains(@class,"ec_desc") or contains(@clas ...

  7. AndroidStudio的一些快捷键的使用

    1.返回上一次浏览快捷键的设置   https://blog.csdn.net/yingtian648/article/details/73277388 2.格式化代码的快捷键的设置      htt ...

  8. OSX - 可以安装任何程序!

    在shell里面执行命令: sudo spctl --master-disable 参考: https://www.jianshu.com/p/010cc30228f3

  9. C - 前m大的数 (结构体)

    点击打开链接 还记得Gardon给小希布置的那个作业么?(上次比赛的1005)其实小希已经找回了原来的那张数表,现在她想确认一下她的答案是否正确,但是整个的答案是很庞大的表,小希只想让你把答案中最大的 ...

  10. flask源码解析之上下文为什么用栈

    楔子 我在之前的文章<flask源码解析之上下文>中对flask上下文流程进行了详细的说明,但是在学习的过程中我一直在思考flask上下文中为什么要使用栈完成对请求上下文和应用上下文的入栈 ...