以下内容摘自下面链接:
http://www.mathworks.cn/help/toolbox/stats/kmeans.html
http://baike.baidu.com/view/3066906.htm
http://en.wikipedia.org/wiki/K-means_clustering
聚类分析(Cluster
Clustering(聚类)
Clustering
训练数据进行学习,这在
举一个简单的例子:现在有一群小学生,你要把他们分成几组,让组内的成员之间尽量相似一些,而组之间则差别大一些。最后分出怎样的结果,就取决于你对于“相似”的定义了(因此,在分类前,一定要知道,每一类的特征到底是什么),比如,你决定男生和男生是相似的,女生和女生也是相似的,而男生和女生之间则差别很大”,这样,你实际上是用一个可能取两个值“男”和“女”的离散变量来代表了原来的一个小学生,我们通常把这样的变量叫做“特征”。实际上,在这种情况下,所有的小学生都被映射到了两个点的其中一个上,已经很自然地形成了两个组,不需要专门再做聚类了。另一种可能是使用“身高”这个特征。我在读小学候,每周五在操场开会训话的时候会按照大家住的地方的地域和距离远近来列队,这样结束之后就可以结队回家了。除了让事物映射到一个单独的特征之外,一种常见的做法是同时提取
聚类分析
聚类分析指将物理或抽象对象的集合分组成为由类似的对象组成的多个类的分析过程。聚类分析的目标就是在相似的基础上收集数据来分类。在不同的应用领域,很多聚类技术都得到了发展,这些技术方法被用作描述数据,衡量不同数据源间的相似性,以及把数据源分类到不同的簇中。
Cluster
Cluster
那么让我们再回到
注意:上面的横纵坐标是特征变量,也即,已经把某一数据投影到特征向量空间中。
从数据点的大致形状可以看出它们大致聚为三个
那么计算机要如何来完成这个任务呢?当然,计算机还没有高级到能够“通过形状大致看出来”,不过,对于这样的
K-means(K-均值聚类法)
K-均值算法表示以空间中k个点为中心进行聚类,对最靠近他们的对象归类。
该算法的最大优势在于简洁和快速。劣势在于对于一些结果并不能够满足需要,因为结果往往需要随机点的选择非常巧合。
算法归纳为(J.
(1)
(2)
如此反复循环,直到凝聚点位置收敛为止
方法特点
通常要求已知类别数
节省运算时间
样本量大于100时有必要考虑
只能使用连续性变量
k-means对于需要进行聚类的数据有一个基本假设:对于每一个
由于这两个分布本身有很大一部分重叠在一起了,例如,对于数据点
基于这样一个假设,我们再来导出k-means
这个函数,其中在数据点
和
来最小化
并不容易,不过我们可以采取迭代的办法:先固定
,选择最优的
,很容易看出,只要将数据点归类到离他最近的那个中心就能保证
最小。下一步则固定
,再求最优的
。将
对
求导并令导数等于零,很容易得到
最小的时候
应该满足:
=mean(xn),其中xn为属于cluster
亦即的值应当是所有
的最小值,因此
只会不断地减小(或者不变),而不会增加,这保证了
下面我们来总结一下
-
选定
K 个中心 的初值。这个过程通常是针对具体的问题有一些启发式的选取方法,或者大多数情况下采用随机选取的办法。因为前面说过k-means
并不能保证全局最优,而是否能收敛到全局最优解其实和初值的选取有很大的关系,所以有时候我们会多次选取初值跑 k-means ,并取其中最好的一次结果。 -
将每个数据点归类到离它最近的那个中心点所代表的
cluster 中。 -
重复第二步,一直到迭代了最大的步数或者前后的
的值相差小于一个阈值为止。
不过正如前面所说的那样
K-means的源码实现
一般情况下,我们通过C++/Matlab/Python等语言进行实现K-means算法,结合近期我刚刚学的C++,先从C++实现谈起,C++里面我们一般采用的是OpenCV库中写好的K-means函数,即cvKmeans2,首先来看函数原型:
从OpenCV manual看到的是:
int cvKMeans2(const CvArr* samples, int nclusters,
CvArr* labels, CvTermCriteria termcrit,
int attempts=1, CvRNG* rng=0,int flags=0,
CvArr* centers=0,double* compactness=0);
由于除去已经确定的参数,我们自己需要输入的为:
void cvKMeans2(
const CvArr* samples, //输入样本的浮点矩阵,每个样本一行。
int cluster_count, //所给定的聚类数目
* labels, //输出整数向量:每个样本对应的类别标识
CvTermCriteria termcrit //指定聚类的最大迭代次数和/或精度(两次迭代引起的聚类中心的移动距离)
);
其使用例程为:
1 #ifdef _CH_ 2 #pragma package <opencv> 3 #endif 4 5 #define CV_NO_BACKWARD_COMPATIBILITY 6 7 #ifndef _EiC 8 #include "cv.h" 9 #include "highgui.h" 10 #include <stdio.h> 11 #endif 12 13 int main( int argc, char** argv ) 14 { 15 #define MAX_CLUSTERS 5 //设置类别的颜色,个数(《=5) 16 CvScalar color_tab[MAX_CLUSTERS]; 17 IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 ); 18 CvRNG rng = cvRNG(-1); 19 CvPoint ipt; 20 21 color_tab[0] = CV_RGB(255,0,0); 22 color_tab[1] = CV_RGB(0,255,0); 23 color_tab[2] = CV_RGB(100,100,255); 24 color_tab[3] = CV_RGB(255,0,255); 25 color_tab[4] = CV_RGB(255,255,0); 26 27 cvNamedWindow( "clusters", 1 ); 28 29 for(;;) 30 { 31 char key; 32 int k, cluster_count = cvRandInt(&rng)%MAX_CLUSTERS + 1; 33 int i, sample_count = cvRandInt(&rng)%1000 + 1; 34 CvMat* points = cvCreateMat( sample_count, 1, CV_32FC2 ); 35 CvMat* clusters = cvCreateMat( sample_count, 1, CV_32SC1 ); 36 cluster_count = MIN(cluster_count, sample_count); 37 38 /** generate random sample from multigaussian distribution */ 39 for( k = 0; k < cluster_count; k++ ) 40 { 41 CvPoint center; 42 CvMat point_chunk; 43 center.x = cvRandInt(&rng)%img->width; 44 center.y = cvRandInt(&rng)%img->height; 45 cvGetRows( points, &point_chunk, k*sample_count/cluster_count, 46 k == cluster_count - 1 ? sample_count : 47 (k+1)*sample_count/cluster_count, 1 ); 48 49 cvRandArr( &rng, &point_chunk, CV_RAND_NORMAL, 50 cvScalar(center.x,center.y,0,0), 51 cvScalar(img->width*0.1,img->height*0.1,0,0)); 52 } 53 54 /** shuffle samples */ 55 for( i = 0; i < sample_count/2; i++ ) 56 { 57 CvPoint2D32f* pt1 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count; 58 CvPoint2D32f* pt2 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count; 59 CvPoint2D32f temp; 60 CV_SWAP( *pt1, *pt2, temp ); 61 } 62 63 printf( "iterations=%d\n", cvKMeans2( points, cluster_count, clusters, 64 cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0 ), 65 5, 0, 0, 0, 0 )); 66 67 cvZero( img ); 68 69 for( i = 0; i < sample_count; i++ ) 70 { 71 int cluster_idx = clusters->data.i[i]; 72 ipt.x = (int)points->data.fl[i*2]; 73 ipt.y = (int)points->data.fl[i*2+1]; 74 cvCircle( img, ipt, 2, color_tab[cluster_idx], CV_FILLED, CV_AA, 0 ); 75 } 76 77 cvReleaseMat( &points ); 78 cvReleaseMat( &clusters ); 79 80 cvShowImage( "clusters", img ); 81 82 key = (char) cvWaitKey(0); 83 if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC' 84 break; 85 } 86 87 cvDestroyWindow( "clusters" ); 88 return 0; 89 } 90 91 #ifdef _EiC 92 main(1,"kmeans.c"); 93 #endif