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

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

  1. 随机生成最初始k个簇心。可以从样本中随机选择,也可以根据样本中每个特征的取值特点随机生成。
  2. 对每个样本计算到每个簇心的欧式距离,将样本划分到欧氏距离最小的簇心(聚点)。
  3. 对划分到同一个簇心(聚点)的样本计算平均值,用均值更新簇心(聚点)
  4. 若某些簇心(聚点)发生变化,转到2;若所有的聚点都没有变化,转5
  5. 输出划分结果
 #include <vector>
#include <cassert>
#include <iostream>
#include <cmath>
#include <fstream>
#include <climits>
#include <ctime>
#include <iomanip> using namespace std;
namespace terse {
class Kmeans {
private:
vector<vector<double>> m_dataSet;
int m_k;
vector<int> m_clusterResult; // result of cluster
vector<vector<double>> m_cluserCent; //center of k clusters private:
vector<string> split(const string& s, string pattern) {
vector<string> res;
size_t start = ;
size_t end = ;
while (start < s.size()) {
end = s.find_first_of(pattern, start);
if (end == string::npos) {
res.push_back(s.substr(start, end - start - ));
return res;
}
res.push_back(s.substr(start, end - start));
start = end + ;
}
return res;
} void loadDataSet(const char* fileName) {
ifstream dataFile(fileName);
if (!dataFile.is_open()) {
cerr << "open file " << fileName << "failed!\n";
return;
}
string tmpstr;
vector<double> data;
while (!dataFile.eof()) {
data.clear();
tmpstr.clear();
getline(dataFile, tmpstr);
vector<string> tmp = split(tmpstr, ",");
for (string str : tmp) {
data.push_back(stod(str));
}
this->m_dataSet.push_back(data);
}
dataFile.close();
} //compute Euclidean distance of two vector
double distEclud(vector<double>& v1, vector<double>& v2) {
assert(v1.size() == v2.size());
double dist = ;
for (size_t i = ; i < v1.size(); i++) {
dist += (v1[i] - v2[i]) * (v1[i] - v2[i]);
}
return sqrt(dist);
} void generateRandCent() {
int numOfFeats = this->m_dataSet[].size();
size_t numOfSamples = this->m_dataSet.size(); //first:min second:max
vector<pair<double, double>> minMaxOfFeat(numOfFeats);
for (int i = ; i < numOfFeats; i++) {
minMaxOfFeat[i].first = this->m_dataSet[][i];
minMaxOfFeat[i].second = this->m_dataSet[][i];
}
for (size_t i = ; i < numOfSamples; i++) {
for (int j = ; j < numOfFeats; j++) {
if (this->m_dataSet[i][j] > minMaxOfFeat[j].second) {
minMaxOfFeat[j].second = this->m_dataSet[i][j];
}
if (this->m_dataSet[i][j] < minMaxOfFeat[j].first) {
minMaxOfFeat[j].first = this->m_dataSet[i][j];
}
}
}
srand(time(NULL));
for (int i = ; i < this->m_k; i++) {
for (int j = ; j < numOfFeats; j++) {
this->m_cluserCent[i][j] = minMaxOfFeat[j].first
+ (minMaxOfFeat[j].second - minMaxOfFeat[j].first)
* (rand() / (double) RAND_MAX);
}
} } void printClusterCent(int iter) {
int m = this->m_cluserCent.size();
int n = this->m_cluserCent[].size();
cout << "iter = " << iter;
for (int i = ; i < m; i++) {
cout << " {";
for (int j = ; j < n; j++) {
cout << this->m_cluserCent[i][j] << ",";
}
cout << "};";
}
cout << endl;
} void writeResult(const char* fileName = "res.txt") {
ofstream fout(fileName);
if (!fout.is_open()) {
cerr << "open file " << fileName << "failed!";
return;
}
for (size_t i = ; i < this->m_dataSet.size(); i++) {
for (size_t j = ; j < this->m_dataSet[].size(); j++) {
fout << this->m_dataSet[i][j] << "\t";
}
fout << setprecision() << this->m_clusterResult[i] << "\n";
}
fout.close();
} public:
Kmeans(int k, const char* fileName) {
this->m_k = k;
this->loadDataSet(fileName);
this->m_clusterResult.reserve(this->m_dataSet.size());
this->m_cluserCent = vector<vector<double>>(k,
vector<double>(this->m_dataSet[].size()));
generateRandCent();
} Kmeans(int k, vector<vector<double>>& data) {
this->m_k = k;
this->m_dataSet = data;
this->m_clusterResult.reserve(this->m_dataSet.size());
this->m_cluserCent = vector<vector<double>>(k,
vector<double>(this->m_dataSet[].size()));
generateRandCent();
} //verbose = 1,printClusterCent();
void kmeansCluster(int verbose = ) {
int iter = ;
bool isClusterChanged = true;
while (isClusterChanged) {
isClusterChanged = false;
//step 1: find the nearest centroid of each point
int numOfFeats = this->m_dataSet[].size();
size_t numOfSamples = this->m_dataSet.size();
for (size_t i = ; i < numOfSamples; i++) {
int minIndex = -;
double minDist = INT_MAX;
for (int j = ; j < this->m_k; j++) {
double dist = distEclud(this->m_cluserCent[j],
m_dataSet[i]);
if (dist < minDist) {
minDist = dist;
minIndex = j;
}
}
if (m_clusterResult[i] != minIndex) {
isClusterChanged = true;
m_clusterResult[i] = minIndex;
}
} //step 2: update cluster center
vector<size_t> cnt(this->m_k, );
this->m_cluserCent = vector<vector<double>>(this->m_k,
vector<double>(numOfFeats, 0.0));
for (size_t i = ; i < numOfSamples; i++) {
for (int j = ; j < numOfFeats; j++) {
this->m_cluserCent[this->m_clusterResult[i]][j] +=
this->m_dataSet[i][j];
}
cnt[this->m_clusterResult[i]]++;
}
// mean of the vector belong to a cluster
for (int i = ; i < this->m_k; i++) {
for (int j = ; j < numOfFeats; j++) {
this->m_cluserCent[i][j] /= cnt[i];
}
}
if (verbose)
printClusterCent(iter++);
}
writeResult();
}
}; }; int main(){
terse::Kmeans kmeans(,"datafile.txt");
kmeans.kmeansCluster();
return ;
}
/*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. SSH中设置字符编码防止乱码

    1.在web.xml中加入一个过滤器和过滤范围的配置 <filter><filter-name>encoding</filter-name><filter-c ...

  2. [FMX]将 Android 程序切换到后台及从后台切换到前台实现

    有时候,我们需要将自己的Android程序切换到后台运行,在必要时,将其切换到前台运行.下面提供了一种实现方式,首先需要引用三个单元:   1 uses Androidapi.JNI.App,Andr ...

  3. 理解go语言 协程之间的通讯

    go已经越来越被重视了,特别适合大型互联网公司基础服务的编写,高效,高并发,可以同时允许多个明星出轨,多个明星结婚 都不在话下,下面介绍下GO协程通讯的过程 直接上代码 package main im ...

  4. 在Asp.net Core中使用中间件来管理websocket

    介绍 ASP.NET Core SignalR是一个有用的库,可以简化Web应用程序中实时通信的管理.但是,我宁愿使用WebSockets,因为我想要更灵活,并且与任何WebSocket客户端兼容. ...

  5. CC2530学习路线-基础实验-GPIO 按键控制LED灯亮灭(2)

    目录 1.前期预备知识 1.1 新大陆Zigbee模块按键电路图 1.2 CC2530相关寄存器 1.3 CC2530中断走向图 1.4 使用C语言为51单片机编写中断程序 1.5 *函数指针 2. ...

  6. 如何用c#本地代码实现与Webbrowser中的JavaScript交互

    关键词:.Net,Webbrowser,JavaScript,communication 参考: 链接:msdn实例-简单的相互调用 代码: [PermissionSet(SecurityAction ...

  7. linux ab压力测试工具及ab命令详解

    原文链接:https://blog.csdn.net/qq_27517377/article/details/78794409 yum -y install httpd-tools ab -v 查看a ...

  8. sql语句_2

    数据表如下 一个user_id对应多个user_name,现在要求是:如果某个用户对应的user_name中存在一个a,打印user_id,a出来:如果不存在,打印user_id,0.打印时候user ...

  9. Flask从入门到精通之Flask表单

    Flask请求对象包含客户端发出的所有请求信息.其中,request.form 能获取POST 请求中提交的表单数据.尽管Flask 的请求对象提供的信息足够用于处理Web 表单,但有些任务很单调,而 ...

  10. day 51 随机验证码, 验证登陆 ,以及 装饰器在函数中的应用

    前端很好的session 的例子 (随机验证码登陆) https://github.com/Endless-Clould/qianduan 参考: 验证码登录 https://www.cnblogs. ...