示范如何用c++实现kmeans
时间: 2025-05-06 20:34:43 浏览: 7
KMeans算法(K均值聚类)是一种常见的无监督学习算法,用于将数据集划分为多个簇。下面是使用C++实现简单版本的K-Means算法:
```cpp
#include <iostream>
#include <vector>
#include <cmath> // for std::pow and std::sqrt
// Define a point in n-dimensional space.
struct Point {
std::vector<double> coordinates;
};
double euclideanDistance(const Point& p1, const Point& p2) {
double sum = 0.0;
if (p1.coordinates.size() != p2.coordinates.size()) return -1; // invalid dimensions
for(size_t i=0;i<p1.coordinates.size();++i){
sum += std::pow(p1.coordinates[i] - p2.coordinates[i], 2);
}
return std::sqrt(sum);
}
class KMeans{
public:
KMeans(int k): num_clusters(k){};
void fit(std::vector<Point>& points,int max_iterations = 100);
private:
int num_clusters;
bool converged();
void assignClusters();
void updateCentroids();
// helper functions to get the average of all values at index d across all Points
double meanDimension(const std::vector<Point>& clusterPoints, size_t dimensionIndex);
std::vector<std::vector<int>> clusters; // List[List[int]]
std::vector<Point> centroids_; // list[Point]
};
void KMeans::fit(std::vector<Point>& data_points ,int max_iterations ){
// Initialize with random Centroid from dataset
srand(time(NULL));
centroids_.resize(num_clusters);
for( auto ¢roid : centroids_ ){
centroid = data_points[rand()%data_points.size()];
}
for(int iter = 0 ;iter<max_iterations;++iter){
assignClusters();
if(converged()){
break ;
}else{
updateCentroids();
}
}
}
bool KMeans::converged(){
// For simplicity this function always returns false but you should check here whether new_centroids are same as old ones within some tolerance limit
return false;
}
void KMeans::assignClusters(){
clusters.resize(num_clusters,std::vector<int>());
for(int idx_point = 0 ;idx_point<data_points.size(); ++idx_point){
int best_cluster_idx=-1;
double min_distance=DBL_MAX;
for(int c_i=0;c_i<num_clusters ;++c_i){
double distance_to_cenroid =euclideanDistance(data_points[idx_point],centroids_[c_i]);
if(distance_to_cenroid <=min_distance){
min_distance =distance_to_cenroid;
best_cluster_idx=c_i;
}
}
clusters[best_cluster_idx].push_back(idx_point);
}
}
void KMeans::updateCentroids(){
for(auto &&cluster_index:clusters | std::views::enumerate ){
auto [index, cluster]=cluster_index;
centroids_[index ].coordinates.clear();
if(cluster.empty())
continue ;
for(unsigned dim =0;dim <data_points.front().coordinates.size(); ++dim){
double avg_dim_value=meanDimension(cluster,dim);
centroids_[index].coordinates.push_back(avg_dim_value );
}
}
}
double KMeans::meanDimension(const std::vector<int>& clusterIndices, size_t dimensionIdx){
if (clusterIndices.empty()) {return 0;}
double total{};
unsigned non_zero{};
for(auto&&pointIdex :clusterIndices){
total+=data_points[pointIdex].coordinates.at(dimensionIdx);
non_zero++;
}
return total/non_zero;
}
```
**给出解释**
该程序实现了以下功能模块:
* `struct Point`表示点的数据结构。
* 函数`euclideanDistance()`计算两点之间的欧几里得距离。
对于类成员变量以及内部函数定义:
* 私有属性包含要形成的簇的数量、当前簇分配情况和质心位置信息;
* 成员函数包括训练模型使用的主方法`fit()`;判断是否收敛的方法`converged()` (这里为了简化直接返回false,在实际应用中你需要根据新旧中心点的位置差异来决定何时终止迭代)、重新指定每个样本所属类别标签的任务由`assignClusters()`完成,并且在每次迭代结束后更新各组新的代表元素即重心坐标的工作交给了`updateCentroids()`去处理。
此外我们还提供了一个辅助工具用来求解特定维度上所有属于同一分组节点坐标的平均值得到下一轮迭代所需的初始参数——`meanDimension()`.
需要注意的是上述示例代码没有对输入进行严格的异常检查与错误处理,这不利于生产环境中部署使用,建议读者进一步完善这部分逻辑使整个系统更加健壮可靠.
阅读全文
相关推荐










