k-means聚类算法C++实现

Clustering 中文翻译作“聚类”,简单地说就是把相似的东西分到一组,同 Classification (分类)不同,对于一个 classifier ,通常需要你告诉它“这个东西被分为某某类”这样一些例子,理想情况下,一个 classifier 会从它得到的训练集中进行“学习”,从而具备对未知数据进行分类的能力,这种提供训练数据的过程通常叫做 supervised learning (监督学习)。而在聚类的时候,我们并不关心某一类是什么,我们需要实现的目标只是把相似的东西聚到一起,因此,一个聚类算法通常只需要知道如何计算相似 度就可以开始工作了,因此 clustering 通常并不需要使用训练数据进行学习,这在 Machine Learning 中被称作 unsupervised learning (无监督学习)。

在数据挖掘中, k-means聚类算法是一种 cluster analysis (聚类分析)的算法,是一种非常简单地基于距离的聚类算法,认为每个Cluster(类)由相似的点组成而这种相似性由距离来衡量,不同Cluster间的点应该尽量不相似,每个Cluster都会有一个“重心”;另外它也是一种排他的算法,即任意点必然属于某一Cluster且只属于该Cluster。

这个算法实现过程很简单,如下图所示:

上图中,A, B, C, D, E 是五个在图中点。而灰色的点是种子点,也就是用来找Cluster的“重心”。有两个种子点,所以K=2。

k-means算法步骤:

      典型的算法如下,它是一种迭代的算法:

      (1)根据事先给定的k值建立初始划分,得到k个Cluster,比如,可以随机选择k个点作为k个Cluster的重心;

      (2)计算每个点到各个Cluster重心的距离,将它加入到最近的那个Cluster;

      (3)重新计算每个Cluster的重心;

      (4)重复过程2~3,直到各个Cluster重心在某个精度范围内不变化或者达到最大迭代次数。

      别看算法简单,很多复杂算法的实际效果或许都不如它,而且它的局部性较好,容易并行化,对大规模数据集很有意义;算法时间复杂度是:O(nkt),其中:n 是聚类点个数,k 是Cluster个数,t 是迭代次数。

k-means算法主要有两个最重大的缺陷,都和初始值有关:

  • K 是事先给定的,这个 K 值的选定是非常难以估计的。很多时候,事先并不知道给定的数据集应该分成多少个类别才最合适。( ISODATA 算法通过类的自动合并和分裂,得到较为合理的类型数目 K)
  • K-Means算法需要用初始随机种子点来搞,这个随机种子点太重要,不同的随机种子点会有得到完全不同的结果。(K-Means++算法可以用来解决这个问题,其可以有效地选择初始点)

k-means算法C++实现:k-means.rar

GitHub代码:https://github.com/luxiaoxun/KMeans-GMM-HMM

代码来源于网络,稍作修改,并做了简单测试。

 

以下是一个简单的C++实现k-means聚类算法的示例代码: ```c++ #include <iostream> #include <vector> #include <cmath> #include <random> //定义一个点的结构体 struct Point { double x, y; int cluster; //点所属簇的编号 }; //计算两个点之间的距离 double distance(Point& a, Point& b) { return std::sqrt(std::pow(a.x - b.x, 2.0) + std::pow(a.y - b.y, 2.0)); } //随机生成k个初始聚类中心 void initClusterCenter(std::vector<Point>& points, std::vector<Point>& clusters, int k) { std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution<int> dis(0, points.size() - 1); for (int i = 0; i < k; ++i) { Point p = points[dis(gen)]; p.cluster = i; clusters.push_back(p); } } //将每个点分配到距离最近的聚类中心所在的簇 void assignCluster(std::vector<Point>& points, std::vector<Point>& clusters) { for (auto& p : points) { double minDistance = distance(p, clusters[0]); int clusterIndex = 0; for (int i = 1; i < clusters.size(); ++i) { double d = distance(p, clusters[i]); if (d < minDistance) { minDistance = d; clusterIndex = i; } } p.cluster = clusterIndex; } } //重新计算每个簇的中心点 void updateClusterCenter(std::vector<Point>& points, std::vector<Point>& clusters) { for (auto& c : clusters) { double sumX = 0.0, sumY = 0.0; int count = 0; for (auto& p : points) { if (p.cluster == c.cluster) { sumX += p.x; sumY += p.y; ++count; } } c.x = sumX / count; c.y = sumY / count; } } //判断聚类是否已经收敛 bool isConverged(std::vector<Point>& oldClusters, std::vector<Point>& newClusters, double epsilon) { for (int i = 0; i < oldClusters.size(); ++i) { if (distance(oldClusters[i], newClusters[i]) > epsilon) { return false; } } return true; } //k-means聚类算法 std::vector<Point> kMeans(std::vector<Point>& points, int k, double epsilon, int maxIterations) { std::vector<Point> clusters; initClusterCenter(points, clusters, k); int iter = 0; while (true) { assignCluster(points, clusters); std::vector<Point> newClusters = clusters; updateClusterCenter(points, newClusters); ++iter; if (isConverged(clusters, newClusters, epsilon) || iter >= maxIterations) { return newClusters; } clusters = newClusters; } } int main() { //生成一些随机点 std::vector<Point> points; for (int i = 0; i < 100; ++i) { Point p; p.x = std::rand() % 100; p.y = std::rand() % 100; points.push_back(p); } //运行k-means聚类 std::vector<Point> clusters = kMeans(points, 3, 0.01, 100); //打印每个簇中的点 for (auto& c : clusters) { std::cout << "Cluster " << c.cluster << ":\n"; for (auto& p : points) { if (p.cluster == c.cluster) { std::cout << "(" << p.x << "," << p.y << ")\n"; } } } return 0; } ``` 这是一个简单的示例,更复杂的应用可能需要更多的优化和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值