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. Flash CC2015软件安装教程

    FLCC2015/64位下载地址: 链接:https://pan.baidu.com/s/1c1WoTTu 密码:k4hn 软件介绍: Flash是一种动画创作与应用程序开发于一身的创作软件.Flas ...

  2. Internal Server Error - http code 500

    Eror Example 1 :  

  3. sqlserver 实现数据变动触发信息

    1.建立存储过程,功能是动态写入文件中信息,可以在触发器或存储过程调用. SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO create proc [d ...

  4. .NET在IE10下的回传BUG修复

    以前我也没注意到,直到有次公司新配了台机器做测试服务器,在测试过程中意外发现凡是涉及PostBack的操作仅在IE10下都无效,其他版本浏览器都没有问题,本机调试也没有问题. 这也就是说在程序相同的情 ...

  5. Dalsa线扫相机SDK下载和安装

    1.首先去官方网站下载SDK Support Downloads - Teledyne DALSA http://www.teledynedalsa.com/imaging/support/downl ...

  6. WebAPI的AuthorizeAttribute扩展类中获取POST提交的数据

    在WEBAPI中,AuthorizeAttribute类重写时,如何获取post数据是个难题,网上找资料也不好使,只能自己研究,通过研究发现,WEBAPI给了我们获取POST数据的可能,下面介绍一下: ...

  7. php类模块引擎PDO操作MySQL数据库简单阐述

    PDO是什么呢? 通俗说就是别人写的一个“数据库操作工具类”,它非常强大,可以应对市面上几乎所有主流数据库, 具体应用时候有这样一个关系: 即,要操作某种数据,就得去“打开”对应的pdo引擎. 在ph ...

  8. python小数的进位与舍去

    一.基础知识准备 ​ 奇进偶舍,又称为四舍六入五成双规则.银行进位法(Banker's Rounding),是一种计数保留法,是一种数值修约规则.从统计学的角度,"奇进偶舍"比&q ...

  9. LOJ#3086. 「GXOI / GZOI2019」逼死强迫症(矩阵快速幂)

    题面 传送门 题解 先考虑全都放\(1\times 2\)的方块的方案,设防\(i\)列的方案数为\(g_i\),容易推出\(g_i=g_{i-1}+g_{i-2}\),边界条件为\(g_0=g_1= ...

  10. Cassandra的数据模型

    Cassandra的数据模型可以理解为嵌套的Map,在Cassandra中数据类型主要有四种:Column,SuperColumn,ColumnFamily,Keyspace.下面分别介绍这几种类型. ...