K-means算法

在使用K-means算法进行聚类时,我们通常需要执行以下步骤:

初始化簇中心、

分配样本点到最近的簇中心、

更新簇中心,直到收敛。

这些步骤可以用C++实现如下:

#include <iostream>
#include <vector>
#include <cmath>
#include <limits>
#include <cstdlib>
#include <ctime>

using namespace std;

// 定义一个简单的点(数据样本)
struct Point {
    double x, y;  // 使用x和y表示点在二维空间中的位置
};

// 计算两个点之间的距离(欧氏距离)
double computeDistance(const Point& a, const Point& b) {
    // 公式:sqrt((x1 - x2)^2 + (y1 - y2)^2)
    return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}

// 初始化簇中心
vector<Point> initializeCentroids(const vector<Point>& points, int k) {
    vector<Point> centroids;
    srand(time(0));  // 利用当前时间作为随机种子,确保每次运行结果不同
    for (int i = 0; i < k; ++i) {
        // 随机选择数据点作为初始的簇中心
        centroids.push_back(points[rand() % points.size()]);
    }
    return centroids;
}

// 分配点到最近的簇中心
vector<int> assignClusters(const vector<Point>& points, const vector<Point>& centroids) {
    vector<int> assignments(points.size());
    for (size_t i = 0; i < points.size(); ++i) {
        double minDistance = numeric_limits<double>::max();  // 初始化为最大值,用于找到最小距离
        int bestCluster = 0;  // 记录当前点所属的最佳簇
        for (size_t j = 0; j < centroids.size(); ++j) {
            double distance = computeDistance(points[i], centroids[j]);
            if (distance < minDistance) {
                minDistance = distance;  // 更新最小距离
                bestCluster = j;  // 更新最佳簇索引
            }
        }
        assignments[i] = bestCluster;  // 将点分配到最近的簇
    }
    return assignments;
}

// 更新簇中心
vector<Point> updateCentroids(const vector<Point>& points, const vector<int>& assignments, int k) {
    vector<Point> newCentroids(k);  // 存储新的簇中心
    vector<int> count(k, 0);  // 存储每个簇的点的数量

    for (size_t i = 0; i < assignments.size(); ++i) {
        newCentroids[assignments[i]].x += points[i].x;
        newCentroids[assignments[i]].y += points[i].y;
        count[assignments[i]]++;  // 增加簇中点的数量
    }

    for (int i = 0; i < k; ++i) {
        if (count[i] != 0) {  // 防止除以零
            newCentroids[i].x /= count[i];  // 计算新簇中心的平均x
            newCentroids[i].y /= count[i];  // 计算新簇中心的平均y
        }
    }
    return newCentroids;
}

// K-means聚类算法
vector<int> kMeansClustering(const vector<Point>& points, int k, int maxIterations = 100) {
    vector<Point> centroids = initializeCentroids(points, k);  // 初始化聚类中心

    for (int it = 0; it < maxIterations; ++it) {
        vector<int> assignments = assignClusters(points, centroids);  // 分配点到簇
        vector<Point> newCentroids = updateCentroids(points, assignments, k);  // 更新簇中心

        // 检查是否已经收敛
        if (newCentroids == centroids)  // 如果新的簇中心没有变化,则算法收敛
            break;
        
        centroids = newCentroids;  // 更新簇中心为新簇中心
    }
    return assignClusters(points, centroids);  // 返回最终的簇分配
}

int main() {
    vector<Point> points = {{1.0, 2.0}, {1.5, 1.8}, {5.0, 8.0}, {8.0, 8.0}, {1.0, 0.6}, {9.0, 11.0}};
    int k = 2;  // 选择将数据分为多少个簇

    vector<int> result = kMeansClustering(points, k);

    for (size_t i = 0; i < result.size(); ++i) {
        cout << "Point (" << points[i].x << ", " << points[i].y << ") is in cluster " << result[i] << endl;
    }

    return 0;
}

 

posted on 2024-12-05 01:47  zhangkele  阅读(2)  评论(0编辑  收藏  举报

导航