K-means 聚类算法是一种常用的无监督学习算法,用于将一组数据分成 K 个类别。以下是一个简单的 C++ 实现。

  1. 定义数据结构

首先需要定义一个数据结构来表示每个数据点。这里我们使用一个简单的结构体来存储数据点的坐标。

struct Point {
  double x, y;
  int cluster;
};

其中,x 和 y 表示数据点的坐标,cluster 表示该点所属的簇。

  1. 初始化数据

接下来需要从输入数据中读取数据点并初始化。

int k = 3; // 要分成的簇的数量
vector<Point> points; // 存储所有数据点的数组

// 从文件中读取数据点
ifstream input("data.txt");
while (!input.eof()) {
  Point p;
  input >> p.x >> p.y;
  p.cluster = -1;
  points.push_back(p);
}
input.close();

// 随机初始化簇的中心点
vector<Point> centroids;
for (int i = 0; i < k; i++) {
  int index = rand() % points.size();
  centroids.push_back(points[index]);
}

这里我们从文件中读取数据点,然后随机初始化簇的中心点。

  1. 迭代计算

接下来需要进行迭代计算,直到簇的中心点不再发生变化为止。

bool changed = true;
while (changed) {
  // 将所有数据点分配到最近的簇
  for (int i = 0; i < points.size(); i++) {
    double min_distance = numeric_limits<double>::max();
    int min_index = -1;
    for (int j = 0; j < centroids.size(); j++) {
      double distance = calculate_distance(points[i], centroids[j]);
      if (distance < min_distance) {
        min_distance = distance;
        min_index = j;
      }
    }
    points[i].cluster = min_index;
  }

  // 计算每个簇的中心点
  vector<Point> new_centroids(k);
  vector<int> count(k);
  for (int i = 0; i < points.size(); i++) {
    new_centroids[points[i].cluster].x += points[i].x;
    new_centroids[points[i].cluster].y += points[i].y;
    count[points[i].cluster]++;
  }
  for (int i = 0; i < k; i++) {
    if (count[i] > 0) {
      new_centroids[i].x /= count[i];
      new_centroids[i].y /= count[i];
    }
  }

  // 判断簇的中心点是否发生变化
  changed = false;
  for (int i = 0; i < k; i++) {
    if (new_centroids[i].x != centroids[i].x || new_centroids[i].y != centroids[i].y) {
      centroids[i] = new_centroids[i];
      changed = true;
    }
  }
}

在每一次迭代中,首先需要将所有数据点分配到最近的簇。然后计算每个簇的中心点,判断簇的中心点是否发生变化。如果发生了变化,则更新簇的中心点并继续迭代,直到簇的中心点不再发生变化为止。

  1. 计算距离

最后,需要定义一个计算两个数据点之间距离的函数。

double calculate_distance(const Point& p1, const Point& p2) {
  double dx = p1.x - p2.x;
  double dy = p1.y - p2.y;
  return sqrt(dx * dx + dy * dy);
}

这个函数使用欧几里得距离计算两个数据点之间的距离。

完整的代码如下:

#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <limits>

using namespace std;

struct Point {
  double x, y;
  int cluster;
};

double calculate_distance(const Point& p1, const Point& p2) {
  double dx = p1.x - p2.x;
  double dy = p1.y - p2.y;
  return sqrt(dx * dx + dy * dy);
}

int main() {
  int k = 3; // 要分成的簇的数量
  vector<Point> points; // 存储所有数据点的数组

  // 从文件中读取数据点
  ifstream input("data.txt");
  while (!input.eof()) {
    Point p;
    input >> p.x >> p.y;
    p.cluster = -1;
    points.push_back(p);
  }
  input.close();

  // 随机初始化簇的中心点
  vector<Point> centroids;
  for (int i = 0; i < k; i++) {
    int index = rand() % points.size();
    centroids.push_back(points[index]);
  }

  bool changed = true;
  while (changed) {
    // 将所有数据点分配到最近的簇
    for (int i = 0; i < points.size(); i++) {
      double min_distance = numeric_limits<double>::max();
      int min_index = -1;
      for (int j = 0; j < centroids.size(); j++) {
        double distance = calculate_distance(points[i], centroids[j]);
        if (distance < min_distance) {
          min_distance = distance;
          min_index = j;
        }
      }
      points[i].cluster = min_index;
    }

    // 计算每个簇的中心点
    vector<Point> new_centroids(k);
    vector<int> count(k);
    for (int i = 0; i < points.size(); i++) {
      new_centroids[points[i].cluster].x += points[i].x;
      new_centroids[points[i].cluster].y += points[i].y;
      count[points[i].cluster]++;
    }
    for (int i = 0; i < k; i++) {
      if (count[i] > 0) {
        new_centroids[i].x /= count[i];
        new_centroids[i].y /= count[i];
      }
    }

    // 判断簇的中心点是否发生变化
    changed = false;
    for (int i = 0; i < k; i++) {
      if (new_centroids[i].x != centroids[i].x || new_centroids[i].y != centroids[i].y) {
        centroids[i] = new_centroids[i];
        changed = true;
      }
    }
  }

  // 输出结果
  for (int i = 0; i < k; i++) {
    cout << "Cluster " << i << ":" << endl;
    for (int j = 0; j < points.size(); j++) {
      if (points[j].cluster == i) {
        cout << "(" << points[j].x << ", " << points[j].y << ")" << endl;
      }
    }
  }

  return 0;
}
C++ 实现 K-means 聚类算法详解

原文地址: https://www.cveoy.top/t/topic/oiiH 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录