• 大小: 7KB
    文件类型: .cpp
    金币: 1
    下载: 0 次
    发布日期: 2021-05-28
  • 语言: C/C++
  • 标签: k-means  

资源简介

k-means多维聚类c++实现

资源截图

代码片段和文件信息

#include 
#include 
#include 
#include 
#include 

using namespace std;
// 数据对象,size为维度
struct Vector
{
  double* coords; // 所有维度的数值
  int     size;//数据维度
  Vector() :  coords(0) size(0) {}
  Vector(int d) { create(d); }
  // 创建维度为d的数据,并将各维度初始化为0
  void create(int d)
  {
    size = d;
    coords = new double[size];//size维,每一维用double类型表示值
    for (int i=0; i      coords[i] = 0.0;
  }
  // 复制一个数据
  void copy(const Vector& other)
  {
    if (size == 0) // 如果原来没有数据,创建之
      create(other.size);
         
    for (int i=0; i      coords[i] = other.coords[i];
  }
  // 将另一个数据的各个维度加在自身的维度上
  void add(const Vector& other)
  {
    for (int i=0; i      coords[i] += other.coords[i];
  }
  // 释放数值的空间
  ~Vector()
  {
    if(coords)
      delete[] coords;
    size = 0;
  }
};
// 聚类结构
struct Cluster
{
  Vector center;    // 中心/引力数据对象
  int*   member;    // 该聚类中各个数据的索引
  int    memberNum; // 数据的数量
};
     
// KMeans算法类
class KMeans
{
private:
  int      num;          // 输入数据的数量
  int      dimen;        // 数据的维数
  int      clusterNum;   // 数据的聚类数
  Vector*  observations; // 所有数据存放在这个数组中
  Cluster* clusters;     // 聚类数组
  int      passNum;      // 迭代的趟数
public:
  // 初始化参数和动态分配内存
  KMeans(int n int d int k Vector* ob)
    : num(n)
     dimen(d)
     clusterNum(k)
     observations(ob)
     clusters(new Cluster[k])
  {
    for (int j=0; j      clusters[j].member = new int[n];//这里为什么每个聚类的数据索引被分配n个指针而不是Cluster.memberNum个?
  }
  // 释放内存
  ~KMeans()
  {
    for (int k=0; k      delete [] clusters[k].member;
    delete [] clusters;
  }
     
  void initClusters()
  {
    // 由于初始数据中心是任意的,
    // 所以直接把前个数据作为NumClusters个聚类的数据中心
    for (int i=0; i    {
      clusters[i].member[0] = i;                // 记录这个数据的索引到第i个聚类中
      clusters[i].center.copy(observations[i]); // 把这个数据作为数据中心
    }
  }
  void run()
  {
    bool converged = false; // 是否收敛
    passNum = 0;
    while (!converged && passNum < 999)   // 如果没有收敛,则再次迭代
                                        // 正常情况下总是会收敛,passNum < 999是防万一
    {
      distribute();                     // 将数据分配到聚中心最近的聚类
      converged = recalculateCenters(); // 计算新的聚类中心,如果计算结果和上次相同,认为已经收敛
      passNum++;
    }
  }
  void distribute()
  {
    // 将上次的记录的该聚类中的数据数量清0,重新开始分配数据
    for(int k=0; k      getCluster(k).memberNum = 0;
    // 找出每个数据的最近聚类数据中心,并将该数据分配到该聚类
    for(int i=0; i    {
      Cluster& cluster = getCluster(closestCluster(i)); // 找出最接近的其中心的聚类
      int memID = cluster.memberNum; // memberNum是当前记录的数据数量,也是新加入数据在member数组中的位置
      cluster.member[memID] = i;     // 将数据索引加入Member数组
      cluster.memberNum++;           // 聚类中的数据数量加1
    }
  }
  int closestCluster(int id)
  {
    int clusterID = 0;               // 暂时假定索引为id的数据最接近第一个聚类
    d

评论

共有 条评论