k-means聚类算法是一种迭代求解的聚类分析算法,其步骤是,预将数据分为K组,然后随机选取K个对象作为初始的聚类中心;计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心;聚类中心以及分配给它们的对象就代表一个聚类;每分配一个样本,聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是没有(或最小数目)对象被重新分配给不同的聚类,没有(或最小数目)聚类中心再发生变化,误差平方和局部最小。
k-means聚类算法在市场分析、图像处理、模式识别、数据挖掘等多个领域中都有广泛应用。通过对数据进行聚类,可以发现数据集中的隐藏结构和规律,进而为决策提供有力支持。以下是一个简单的C++实现,展示了如何使用k-means算法对二维数据进行聚类。请注意,为了简单起见,此实现省略了一些优化和错误处理,但足以说明k-means算法的基本思想。代码如下。
#include <iostream>
#include <vector>
#include <cmath>
#include <random>
#include <limits>
#include <algorithm>struct Point {double x, y;
};double euclideanDistance(const Point& a, const Point& b) {return std::sqrt(std::pow(a.x - b.x, 2) + std::pow(a.y - b.y, 2));
}Point calculateCentroid(const std::vector<Point>& cluster) {double sumX = 0, sumY = 0;for (const auto& point : cluster) {sumX += point.x;sumY += point.y;}return {sumX / cluster.size(), sumY / cluster.size()};
}std::vector<Point> initializeCentroids(const std::vector<Point>& data, int k) {std::vector<Point> centroids(k);std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<> dis(0, data.size() - 1);for (int i = 0; i < k; ++i) {centroids[i] = data[dis(gen)];}return centroids;
}std::vector<std::vector<Point>> kMeans(const std::vector<Point>& data, int k, int maxIterations) {std::vector<Point> centroids = initializeCentroids(data, k);std::vector<std::vector<Point>> clusters(k);for (int iter = 0; iter < maxIterations; ++iter) {// Assign points to clustersstd::fill(clusters.begin(), clusters.end(), std::vector<Point>());for (const auto& point : data) {int minIndex = -1;double minDist = std::numeric_limits<double>::max();for (int i = 0; i < k; ++i) {double dist = euclideanDistance(point, centroids[i]);if (dist < minDist) {minDist = dist;minIndex = i;}}clusters[minIndex].push_back(point);}// Calculate new centroidsbool hasConverged = true;for (int i = 0; i < k; ++i) {Point oldCentroid = centroids[i];centroids[i] = calculateCentroid(clusters[i]);if (euclideanDistance(oldCentroid, centroids[i]) > std::numeric_limits<double>::epsilon()) {hasConverged = false;}}if (hasConverged) {break;}}return clusters;
}int main() {// Sample data pointsstd::vector<Point> data = {{1, 2}, {5, 8}, {1.5, 1.8}, {8, 8}, {1, 0.6}, {9, 11}};// Number of clusters and maximum iterationsint k = 2;int maxIterations = 100;// Perform k-means clusteringstd::vector<std::vector<Point>> clusters = kMeans(data, k, maxIterations);// Print resultsstd::cout << "Clusters:" << std::endl;for (int i = 0; i < clusters.size(); ++i) {std::cout << "Cluster " << i + 1 << ":" << std::endl;for (const auto& point : clusters[i]) {std::cout << "(" << point.x << ", " << point.y << ")" << std::endl;}std::cout << std::endl;}// Optionally, print centroidsstd::cout << "Centroids:" << std::endl;for (const auto& centroid : kMeans(data, k, maxIterations)[0]) {std::cout << "(" << centroid.x << ", " << centroid.y << ")" << std::endl;}return 0;
}
以上代码首先定义了一个`Point`结构体用于表示二维空间中的点,然后定义了几个辅助函数,包括计算欧几里得距离、计算聚类中心、初始化聚类中心等。`kMeans`函数实现了k-means算法的主要逻辑,包括分配点到聚类中以及重新计算聚类中心。`main`函数中创建了一些样本数据点,然后调用`kMeans`函数进行聚类,并打印出每个聚类中的点以及聚类中心。
注意:在实际应用中,k-means算法可能需要更多的优化,例如使用更高效的初始化方法(如k-means++),处理空聚类,以及利用并行计算加速算法等。此外,对于大规模数据集或高维数据,可能需要使用更高级的聚类算法。此示例仅用于展示k-means算法的基本实现。