动态聚类中 C-均值算法 (K-均值算法)的C++实现

原创 2006年06月20日 15:21:00

一:说明

动态聚类方法是模式识别中一种普遍采用的方法,它具有以下3个要点:

    1:选定某种距离度量作为样本间的相似性度量

    2:确定某个评价聚类结果质量的准则函数

    3:给定某个初始分类,然后用迭代算法找出使准则函数取极值的最好的聚类结果

本文给出了 C-均值算法 的 C++  实现。

(算法描述参见  边肇祺  张学工等  << 模式识别 >> P237 清华大学出版社)

 

二:源码

 

2.1  头文件

 

#pragma once

#include <list>

#include <vector>

using namespace std;

#define DATANUM 19

#define MAXDIST 333333

 

struct CData

{

    int x1;

    int x2;

};

 

 

class CCMean

{

public:

    CCMean(CData *pdata);

    ~CCMean(void);

    void init(); 

    void work(int InitClassNum);

 

private:

    // calculate the mean of class i:

    void CalcuMean( int i );

 

    // calculate the ERROR of class i:

    void CalcuJc(int i);

    void CalcuJe();

 

    // step 1 of C-Mean algorithm

    void InitDeploy();

 

    // step 4 and 5 of C-Mean algorithm

    // da is now in class i,

    // return ture when moving da from class to class k

    // return false when we do not move da

    bool MoveItoK( const CData& da, int i, int &k );

 

    // calculate the distance of to data:

    int  dist( const CData& mean, const CData& da);

 

    // print result:

    void OutPut();

 

 

    // iClassNum is the initial class number, in text book, iClassNum <==> C

    int iClassNum;

 

    // pointer to data array:

    CData *pData;

 

    // store the mean of all classes. just ueses 0 to iClassNum - 1;

    // in text book is: m1, m2, m3, m4, ... , mc.

    CData mean[DATANUM];

 

    // store the ERROR of each class, just ueses 0 to iClassNum - 1;

    // the sum of jc[0] to jc[iClassNum - 1] will be je defined following jc;

    int jc[DATANUM];

 

    //the sum of jc[0] to jc[iClassNum - 1]

    int je;

 

    // pcla[i] pointer class i which store in LIST

    list< CData >* pcla[DATANUM];

 

};

 

2.2  实现文件

 

 

#include "assert.h"

#include "cmean.h"

 

CCMean::CCMean(CData *pdata)

{

    pData = pdata;

    for(int i = 0; i < DATANUM; i ++ )

    {

       pcla[i] = new list< CData >;

       assert( pcla[i] != 0 );

    }

    je = 0;

}

 

CCMean::~CCMean()

{

    for(int i = 0; i < DATANUM; i ++ )

       delete pcla[i];

}

void CCMean::init()

{

    for(int i = 0; i < DATANUM; i ++ )

    {

       pcla[i]->clear();

       mean[i].x1 = 0;

       mean[i].x2 = 0;

    }

    je = 0;

}

 

void CCMean::CalcuMean(int ii)

{

    int sum1 = 0, sum2 = 0;

    int si = (int)pcla[ii]->size();

 

    list< CData >::iterator iter = pcla[ii]->begin();

    for(int i = 0; i < si; i ++ )

    {

       sum1 += iter->x1;

       sum2 += iter->x2;

       iter++;

    }

    mean[ii].x1 = sum1 / si;

    mean[ii].x2 = sum2 / si;

}

 

void CCMean::CalcuJe()

{

    for( int i = 0; i < iClassNum ; i ++ )

    {

       CalcuJc( i );

       je += jc[i];

    }         

}

 

void CCMean::CalcuJc( int index )

{

    list< CData >::iterator iter = pcla[index]->begin();

    int si = (int)pcla[index]->size();

 

 

    jc[index] = 0;

    for( int i = 0; i < si; i ++)

    {

       jc[index] += dist( mean[index], *iter );

       iter ++;

    }

}

 

int CCMean::dist(const CData& mean, const CData& da)

{

    return (mean.x1 - da.x1)*(mean.x1 - da.x1) + (mean.x2 - da.x2)*(mean.x2 - da.x2);

}

 

void CCMean::InitDeploy()

{

    CData *ptem = pData;

    for( int i = 0; i < iClassNum; i ++ )

    {

       // choose the first iClassNum data as our initial class-center:

       mean[i] = *ptem;

       pcla[i]->push_back( *ptem );

       ptem++;

    }

 

    // put other data to our initial classes:

    for( int i = iClassNum; i < DATANUM; i ++ )

    {

       int mindis = MAXDIST;

       int pos = 0;

 

       // get the least distance between pData[i] and m1, m2, m3 ....

       for( int j = 0; j < iClassNum; j ++ )

       {

           int curdis = dist( pData[i], mean[j] );

           if( curdis < mindis )

           {

              mindis = curdis;

              pos = j;

           }

       }

       // add pData to class (pos):

       pcla[pos]->push_back( pData[i] );

    }

 

    for( int i = 0; i < iClassNum ; i ++ )

       CalcuMean( i );

 

    CalcuJe();

}

 

 

bool CCMean::MoveItoK( const CData &da, int i , int& k )

{

    // now da is in class i,if da is moved to another class, return true, else return false

    int Pk = MAXDIST;

    int Pj = 0;

    int temk = 0;

    for( int j = 0; j < iClassNum; j ++ )

    {

       int si = (int)pcla[j]->size();

       if( j == i )

           Pj = dist( mean[j], da ) * si/(si - 1);

       else

           Pj = dist( mean[j], da ) * si/(si + 1);

       if( Pj < Pk ) 

       {

           Pk = Pj;

           temk = j;

       }

       else if ( Pj == Pk  && j == i )

       {

           // when Pj == Pk && j == i, we do not move (da) from class i to class j

           temk = i;

       }

    }

 

    if( i == temk )

       return false; // we do NOT move da;

 

    k = temk;

    // add da to class k:

    pcla[k]->push_back( da );

 

    // delete da from class i, first find the positon of da in class i:

    list< CData >::iterator iter = pcla[i]->begin();

    while( iter != pcla[i]->end() )

    {

       if( iter->x1 == da.x1 && iter->x2 == da.x2 )

           break;

       iter++;

    }

 

    // now delete da from class i:

    pcla[i]->erase( iter );

 

    // we have move da from class i to class k;

    return true;

}

 

void CCMean::OutPut()

{

    for( int i = 0; i < iClassNum ; i ++ )

    {

       printf("class %d:/n", i );

       list< CData >::iterator iter = pcla[i]->begin();

       int j = 1;

       while( iter != pcla[i]->end() )

       {

           printf( "(%d,  %d)       ", iter->x1, iter->x2 );

           iter ++;

           if( j++ % 5 == 0)

              printf("/n");

       }

       printf("/n");

    }

}

 

void CCMean::work(int InitClassNum)

{

    iClassNum = InitClassNum;

 

    // step 1 of C-Mean algorithm

    InitDeploy();

   

    int counter = 0;

Again:

    //OutPut();

    // step 2 of C-Mean algorithm: choose one sample y (here is da) from collection

    for( int i = 0; i < iClassNum ; i ++ )

    {

       // step 3 of C-Mean algorithm:

       int si = (int)pcla[i]->size();

       if( si == 1 )

           continue;

 

       // step 4 of C-Mean algorithm:

       list< CData >::iterator iter = pcla[i]->begin();

       for(int j = 0; j < (int)pcla[i]->size(); j++)

       {

           int k = 0;

           CData da = *iter;

           iter ++;

 

           // step 5 of C-Mean algorithm:

           if( MoveItoK( da , i, k ) == true )

           {

              // step 6 of C-Mean algorithm:

              int OldJe = je;

              je -= jc[i];

              je -= jc[k];

 

              CalcuMean( i );

              CalcuMean( k );

 

              CalcuJc( i );

              CalcuJc( k );

 

              je += jc[i];

              je += jc[k];

              if( OldJe > je )

              {

                  counter = 0;

                    goto Again;

              }

           }

           counter++;

           // step 7 of C-Mean algorithm:

           if( counter == DATANUM )

              goto end;

       }

    }

end:

    printf(" current Je is: %d/n", je );

    OutPut();

}

 

2.3  测试文件

 

#include "CMean.h"

#include "process.h"

 

CData yy[DATANUM] =

{

     {0,0},{0,1},{1,0},{1,1},{1,2},{2,1},{2,2},{2,3}

    ,{6,6},{6,7},{6,8},{7,6},{7,7},{7,8},{7,9},{8,7}

    ,{8,8},{8,9},{9,8}

};

 

int main(int argc, char* argv[])

{

    CCMean cmean( yy );

 

    cmean.work(2);

    system("pause");

    return 0;

}

聚类算法(一):k-均值 (k-means)算法

首先确保你在动手写代码之前已经了解什么是聚类分析。 k-均值算法----一种基于形心地技术的聚类算法。k-均值算法的英文名是k-means,那么这个算法是怎么工作的呢? k-均值算法把簇的形心定义为簇...
  • chixujohnny
  • chixujohnny
  • 2015年12月16日 20:23
  • 1688

K均值聚类算法(K-Means)

K均值聚类算法(K-Means)标签: Python 机器学习1.K均值算法简介K均值聚类算法首先是聚类算法。 聚类是一种无监督的学习,将相似的对象归到同一个簇中。聚类与分类的最大不同在于分类的目...
  • xuelabizp
  • xuelabizp
  • 2016年07月10日 17:37
  • 14685

FCM 模糊C均值聚类算法

首先FCM在图像分割领域有很多应用,FCM算法我觉得主要是两个部分,一个是模糊理论,一个是C/Kmean算法,这两者在数学家手中完美的结合。 下面切入整体,我也是为了温故才写的这篇博客,如有错误或者瑕...
  • fclovw
  • fclovw
  • 2016年08月27日 15:31
  • 1605

模式识别:k-均值聚类算法的研究与实现

本实验的目的是学习和掌握k-均值聚类算法。k-均值算法是一种经典的无监督聚类和学习算法,它属于迭代优化算法的范畴。本实验在MATLAB平台上,编程实现了k-均值聚类算法,并使用20组三维数据进行测试,...
  • liyuefeilong
  • liyuefeilong
  • 2015年06月10日 20:41
  • 6625

模糊C均值聚类算法及实现

FCM http://wenku.baidu.com/view/ee968c00eff9aef8941e06a2.html mean-shift http://wenku.baidu...
  • zhangpinghao
  • zhangpinghao
  • 2013年04月07日 16:27
  • 1218

模糊C均值聚类

 模糊C均值聚类(FCM),即众所周知的模糊ISODATA,是用隶属度确定每个数据点属于某个聚类的程度的一种聚类算法。1973年,Bezdek提出了该算法,作为早期硬C均值聚类(HCM)方法的一种改进...
  • xiaoyu50052
  • xiaoyu50052
  • 2006年11月20日 21:57
  • 12088

二分K均值c++实现

二分k均值原理及Python实现请见: (1)http://blog.csdn.net/u013593585/article/details/51280052 (2)http://blog.csdn....
  • u013593585
  • u013593585
  • 2016年05月12日 21:08
  • 558

K-均值算法简介

本文名为K-均值算法简介,除包含算法内容以外,还包含了K-均值算法的来源、关于K-均值算法的不同视角,以及应用和优缺点方面的内容。...
  • qingdanry
  • qingdanry
  • 2015年04月14日 15:09
  • 4172

聚类分析之模糊C均值算法核心思想

聚类分析中存在一种方法:‘模糊C均值’,模糊C均值的发现,要感谢模糊数学之父“扎德”老爷子,他老人家当年提出了“模糊集合论”和“模糊逻辑”,介绍算法之前,先简单的补充一些相关的知识点.       ...
  • u014028070
  • u014028070
  • 2016年06月27日 13:13
  • 1173

模糊C均值聚类以及C实现

1. 基本介绍 同K均值类似,FCM算法也是一种基于划分的聚类算法,它的思想就是使得被划分到同一簇的对象之间相似度最大,而不同簇之间的相似度最小。 模糊C均值是普通C均值聚类算法的改进,普通C均值...
  • einsdrw
  • einsdrw
  • 2014年07月18日 15:35
  • 7867
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:动态聚类中 C-均值算法 (K-均值算法)的C++实现
举报原因:
原因补充:

(最多只允许输入30个字)