聚类分析及k均值聚类



以下内容摘自下面链接: 

http://blog.pluskid.org/?p=17

http://www.mathworks.cn/help/toolbox/stats/kmeans.html

http://www.mathworks.cn/products/image/demos.html?file=/products/demos/shipping/images/ipexhistology.html

http://baike.baidu.com/view/3066906.htm

http://en.wikipedia.org/wiki/K-means_clustering


聚类分析(Cluster analysis 

Clustering(聚类) 和Classification(分类)

Clustering 中文翻译作“聚类”,简单地说就是把相似的东西分到一组,同Classification(分类)不同,对于一个 classifier ,通常需要你告诉它“这个东西被分为某某类”这样一些例子,理想情况下,一个 classifier 会从它得到的训练集中进行“学习”,从而具备对未知数据进行分类的能力,这种提供训练数据的过程通常叫做 supervised learning (监督学习),而在聚类的时候,我们并不关心某一类是什么,我们需要实现的目标只是把相似的东西聚到一起,因此,一个聚类算法通常只需要知道如何计算相似 度就可以开始工作了,因此 clustering 通常并不需要使用

训练数据进行学习,这在 Machine Learning 中被称作 unsupervised learning (无监督学习)。

举一个简单的例子:现在有一群小学生,你要把他们分成几组,让组内的成员之间尽量相似一些,而组之间则差别大一些。最后分出怎样的结果,就取决于你对于“相似”的定义了(因此,在分类前,一定要知道,每一类的特征到底是什么),比如,你决定男生和男生是相似的,女生和女生也是相似的,而男生和女生之间则差别很大”,这样,你实际上是用一个可能取两个值“男”和“女”的离散变量来代表了原来的一个小学生,我们通常把这样的变量叫做“特征”。实际上,在这种情况下,所有的小学生都被映射到了两个点的其中一个上,已经很自然地形成了两个组,不需要专门再做聚类了。另一种可能是使用“身高”这个特征。我在读小学候,每周五在操场开会训话的时候会按照大家住的地方的地域和距离远近来列队,这样结束之后就可以结队回家了。除了让事物映射到一个单独的特征之外,一种常见的做法是同时提取 种特征,将它们放在一起组成一个 维向量(特征向量),从而得到一个从原始数据集合到 维向量空间的映射——你总是需要显式地或者隐式地完成这样一个过程,因为许多机器学习的算法都需要工作在一个向量空间中。

 

聚类分析

聚类分析指将物理或抽象对象的集合分组成为由类似的对象组成的多个类的分析过程。聚类分析的目标就是在相似的基础上收集数据来分类。在不同的应用领域,很多聚类技术都得到了发展,这些技术方法被用作描述数据,衡量不同数据源间的相似性,以及把数据源分类到不同的簇中。

Cluster analysis or clustering is the task of assigning set of objects into groups (called clusters) so that the objects in the same cluster are more similar (in some sense or another) to each other than to those in other clusters.[1]

Cluster analysis itself is not one specific algorithm, but the general task to be solved. It can be achieved by various algorithms that differ significantly in their notion of what constitutes cluster and how to efficiently find them. Popular notions of clusters include groups with low distances among the cluster members, dense areas of the data space, intervals or particular statistical distributions. Clustering can therefore be formulated as multi-objective optimization problem. The appropriate clustering algorithm and parameter settings (including values such as the distance function to use, density threshold or the number of expected clusters) depend on the individual data set and intended use of the results. Cluster analysis as such is not an automatic task, but an iterative process of knowledge discovery or interactive multi-objective optimization that involves trial and failure. It will often be necessary to modify preprocessing and parameters until the result achieves the desired properties.

那么让我们再回到 clustering 的问题上,暂且抛开原始数据是什么形式,假设我们已经将其映射到了一个欧几里德空间上,为了方便展示,就使用二维空间吧,如下图所示:

聚类分析及k均值聚类(K-means)简介zz

注意:上面的横纵坐标是特征变量,也即,已经把某一数据投影到特征向量空间中。

从数据点的大致形状可以看出它们大致聚为三个 cluster ,其中两个紧凑一些,剩下那个松散一些。我们的目的是为这些数据分组,以便能区分出属于不同的簇的数据,如果按照分组给它们标上不同的颜色,就是这个样子:

聚类分析及k均值聚类(K-means)简介zz

那么计算机要如何来完成这个任务呢?当然,计算机还没有高级到能够“通过形状大致看出来”,不过,对于这样的 维欧氏空间中的点进行聚类,有一个非常简单的经典算法,也就是本文标题中提到的k-means 

 

K-means(K-均值聚类法)

K-均值算法表示以空间中k个点为中心进行聚类,对最靠近他们的对象归类。

该算法的最大优势在于简洁和快速。劣势在于对于一些结果并不能够满足需要,因为结果往往需要随机点的选择非常巧合。

算法归纳为(J. MacQueen, 1967):
(1)  初始化:选择(或人为指定)某些记录作为凝聚点 
(2)  循环: 
      2.1  按就近原则将其余记录向凝聚点凝集 
      2.2  计算出各个初始分类的中心位置(均值) 
      2.3  用计算出的中心位置重新进行聚类 
如此反复循环,直到凝聚点位置收敛为止 

方法特点 
  通常要求已知类别数 
  节省运算时间 
  样本量大于100时有必要考虑 
  只能使用连续性变量

 

k-means对于需要进行聚类的数据有一个基本假设:对于每一个 cluster ,我们可以选出一个中心点 (center),使得该 cluster 中的所有的点到该中心点的距离小于到其他 cluster 的中心的距离。虽然实际情况中得到的数据并不能保证总是满足这样的约束,但这通常已经是我们所能达到的最好的结果,而那些误差通常是固有存在的或者问题本身的不可分性造成的。例如下图所示的两个高斯分布,从两个分布中随机地抽取一些数据点出来,混杂到一起,现在要让你将这些混杂在一起的数据点按照它们被生成的那个分布分开来:

聚类分析及k均值聚类(K-means)简介zz

由于这两个分布本身有很大一部分重叠在一起了,例如,对于数据点 2.5 来说,它由两个分布产生的概率都是相等的,你所做的只能是一个猜测;稍微好一点的情况是 ,通常我们会将它归类为左边的那个分布,因为概率大一些,然而此时它由右边的分布生成的概率仍然是比较大的,我们仍然有不小的几率会猜错。而整个阴影部分是我们所能达到的最小的猜错的概率,这来自于问题本身的不可分性,无法避免。因此,我们将 k-means 所依赖的这个假设看作是合理的。

基于这样一个假设,我们再来导出k-means 所要优化的目标函数:设我们一共有 个数据点需要分为 个 cluster ,k-means 要做的就是最小化

聚类分析及k均值聚类(K-means)简介zz

这个函数,其中聚类分析及k均值聚类(K-means)简介zz在数据点 被归类到 cluster 的时候为 ,否则为 。直接寻找聚类分析及k均值聚类(K-means)简介zz聚类分析及k均值聚类(K-means)简介zz来最小化聚类分析及k均值聚类(K-means)简介zz并不容易,不过我们可以采取迭代的办法:先固定聚类分析及k均值聚类(K-means)简介zz,选择最优的聚类分析及k均值聚类(K-means)简介zz,很容易看出,只要将数据点归类到离他最近的那个中心就能保证聚类分析及k均值聚类(K-means)简介zz最小。下一步则固定聚类分析及k均值聚类(K-means)简介zz,再求最优的聚类分析及k均值聚类(K-means)简介zz。将聚类分析及k均值聚类(K-means)简介zz聚类分析及k均值聚类(K-means)简介zz求导并令导数等于零,很容易得到聚类分析及k均值聚类(K-means)简介zz最小的时候聚类分析及k均值聚类(K-means)简介zz应该满足:

聚类分析及k均值聚类(K-means)简介zz

=mean(xn),其中xn为属于cluster k的点的坐标

亦即聚类分析及k均值聚类(K-means)简介zz的值应当是所有 cluster 中的数据点的平均值。由于每一次迭代都是取到 聚类分析及k均值聚类(K-means)简介zz的最小值,因此 聚类分析及k均值聚类(K-means)简介zz只会不断地减小(或者不变),而不会增加,这保证了 k-means 最终会到达一个极小值。虽然 k-means 并不能保证总是能得到全局最优解,但是对于这样的问题,像 k-means 这种复杂度的算法,这样的结果已经是很不错的了。

下面我们来总结一下 k-means 算法的具体步骤:

  1. 选定 个中心聚类分析及k均值聚类(K-means)简介zz的初值。这个过程通常是针对具体的问题有一些启发式的选取方法,或者大多数情况下采用随机选取的办法。因为前面说过k-means 并不能保证全局最优,而是否能收敛到全局最优解其实和初值的选取有很大的关系,所以有时候我们会多次选取初值跑 k-means ,并取其中最好的一次结果。

  2. 将每个数据点归类到离它最近的那个中心点所代表的 cluster 中。

  3. 用公式聚类分析及k均值聚类(K-means)简介zz 计算出每个 cluster 的新的中心点。

  4. 重复第二步,一直到迭代了最大的步数或者前后的聚类分析及k均值聚类(K-means)简介zz的值相差小于一个阈值为止。

不过正如前面所说的那样 k-means 也并不是万能的,虽然许多时候都能收敛到一个比较好的结果,但是也有运气不好的时候会收敛到一个让人不满意的局部最优解


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
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值