C++: 实现聚类算法(附带源码)

项目介绍

聚类是无监督学习中一种常用的算法,用于将数据集中的对象分组(称为簇),使得同一簇中的对象相似度较高,而不同簇之间的对象相似度较低。在许多领域,如数据挖掘、图像处理和模式识别等,聚类算法都有广泛应用。

在本项目中,我们将实现最常见的聚类算法之一——K均值聚类(K-Means Clustering)。该算法的目标是通过迭代的方式将数据集划分为 K 个簇,每个簇由其中心(均值)表示。

项目实现思路

  1. 输入参数

    • 用户提供数据点(二维坐标或多维向量)以及聚类的簇数 K。
  2. K均值算法

    • 随机初始化 K 个簇中心。
    • 分配每个数据点到距离其最近的簇中心。
    • 计算每个簇的均值,并更新簇中心。
    • 重复上述过程,直到簇中心不再变化(收敛)。
  3. 距离计算

    • 使用欧几里得距离计算数据点与簇中心之间的距离。
  4. 输出结果

    • 输出每个数据点所属的簇,以及每个簇的中心。

项目实现代码

#include 
#include 
#include 
#include 
#include 

struct Point {
    double x, y;
    int cluster; // 保存该点所属的簇编号
};

// 计算两点之间的欧几里得距离
double euclideanDistance(const Point& p1, const Point& p2) {
    return std::sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}

// K均值聚类算法
void kMeans(std::vector& points, int K) {
    int n = points.size();
    std::vector centroids(K); // 存储簇中心
    std::vector pointCounts(K, 0); // 记录每个簇的点数

    // 随机初始化K个簇中心
    std::srand(std::time(0));
    for (int i = 0; i < K; ++i) {
        centroids[i] = points[std::rand() % n]; // 随机选取数据点作为簇中心
    }

    bool converged = false;
    while (!converged) {
        // 步骤1:为每个数据点分配簇
        for (auto& point : points) {
            double minDistance = std::numeric_limits::max();
            int closestCluster = -1;
            for (int i = 0; i < K; ++i) {
                double dist = euclideanDistance(point, centroids[i]);
                if (dist < minDistance) {
                    minDistance = dist;
                    closestCluster = i;
                }
            }
            point.cluster = closestCluster;
        }

        // 步骤2:更新每个簇的中心
        std::vector newCentroids(K, {0.0, 0.0});
        std::fill(pointCounts.begin(), pointCounts.end(), 0); // 重置每个簇的点数

        for (const auto& point : points) {
            newCentroids[point.cluster].x += point.x;
            newCentroids[point.cluster].y += point.y;
            pointCounts[point.cluster]++;
        }

        // 计算新的簇中心
        for (int i = 0; i < K; ++i) {
            if (pointCounts[i] > 0) {
                newCentroids[i].x /= pointCounts[i];
                newCentroids[i].y /= pointCounts[i];
            }
        }

        // 判断簇中心是否变化,如果没有变化则表示收敛
        converged = true;
        for (int i = 0; i < K; ++i) {
            if (euclideanDistance(centroids[i], newCentroids[i]) > 1e-6) {
                converged = false;
                break;
            }
        }

        centroids = newCentroids; // 更新簇中心
    }
}

void printClusters(const std::vector& points) {
    for (const auto& point : points) {
        std::cout << "Point (" << point.x << ", " << point.y << ") is in cluster " << point.cluster << std::endl;
    }
}

int main() {
    // 测试数据:一组二维点
    std::vector points = {
        {1.0, 2.0, -1}, {1.5, 1.8, -1}, {5.0, 8.0, -1}, {8.0, 8.0, -1},
        {1.0, 0.6, -1}, {9.0, 11.0, -1}, {8.0, 2.0, -1}, {10.0, 2.0, -1},
        {9.0, 3.0, -1}, {7.0, 5.0, -1}
    };

    int K = 3; // 设置簇的数量

    // 执行K均值聚类
    kMeans(points, K);

    // 输出聚类结果
    printClusters(points);

    return 0;
}

代码解释

  1. Point 结构体

    • xy 是数据点的坐标,cluster 是该点所属的簇编号。
  2. euclideanDistance 函数

    • 计算两点之间的欧几里得距离,这是 K均值算法中用于度量点与簇中心之间距离的标准方法。
  3. kMeans 函数

    • 该函数实现了 K 均值聚类的主要逻辑。
    • 随机选择 K 个簇中心。
    • 在每次迭代中,将每个数据点分配到距离其最近的簇中心。
    • 然后计算新的簇中心,并检查是否收敛(即簇中心不再变化)。
  4. printClusters 函数

    • 打印每个数据点所属的簇及其坐标。
  5. main 函数

    • 定义了一组二维数据点,并指定了簇的数量 K=3。
    • 调用 kMeans 函数来执行聚类,并通过 printClusters 函数输出聚类结果。

项目总结

通过本项目,我们实现了 K 均值聚类算法,并应用于二维数据点的聚类问题。算法通过随机初始化簇中心,然后通过迭代方式将数据点分配到簇中,并更新簇中心,直到簇中心收敛。最终,算法输出每个数据点所属的簇。

优化与扩展

  1. 初始化优化

    • 当前实现中,簇中心是随机选择的。这可能导致算法陷入局部最优解。可以使用 K-Means++ 方法来优化初始化过程,增加收敛到全局最优的概率。
  2. 高维数据支持

    • 当前实现支持二维数据。可以扩展为支持任意维度的数据。
  3. 性能优化

    • 在大数据集上,当前的实现可能会较慢。可以使用更高效的数据结构(如 KD-Tree)来加速最近邻查找。
  4. 并行化

    • 对于大数据集,可以利用多线程或 GPU 来加速 K 均值聚类算法的执行,特别是在计算簇中心时,可以并行处理。

示例输出

假设输入数据点如下:

Point (1, 2) is in cluster 0
Point (1.5, 1.8) is in cluster 0
Point (5, 8) is in cluster 1
Point (8, 8) is in cluster 1
Point (1, 0.6) is in cluster 0
Point (9, 11) is in cluster 2
Point (8, 2) is in cluster 1
Point (10, 2) is in cluster 1
Point (9, 3) is in cluster 1
Point (7, 5) is in cluster 1

这个输出表明,数据点被正确地分配到各自的簇中,簇编号从 0 到 2,分别表示不同的簇。

你可能感兴趣的:(c,c++实现算法,算法,聚类,支持向量机)