原文地址:http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006910.html
K-means也是聚类算法中最简单的一种了,但是里面包含的思想却是不一般。最早我使用并实现这个算法是在学习韩爷爷那本数据挖掘的书中,那本书比较注重应用。看了Andrew Ng的这个讲义后才有些明白K-means后面包含的EM思想。
聚类属于无监督学习,以往的回归、朴素贝叶斯、SVM等都是有类别标签y的,也就是说样例中已经给出了样例的分类。而聚类的样本中却没有给定y,只有特征x,比如假设宇宙中的星星可以表示成三维空间中的点集。聚类的目的是找到每个样本x潜在的类别y,并将同类别y的样本x放在一起。比如上面的星星,聚类后结果是一个个星团,星团里面的点相互距离比较近,星团间的星星距离就比较远了。
K-means算法是将样本聚类成k个簇(cluster),具体算法描述如下:
1、 随机选取k个聚类质心点(cluster centroids)为。 2、 重复下面过程直到收敛 { 对于每一个样例i,计算其应该属于的类 对于每一个类j,重新计算该类的质心 } |
K是我们事先给定的聚类数,代表样例i与k个类中距离最近的那个类,的值是1到k中的一个。质心代表我们对属于同一个类的样本中心点的猜测,拿星团模型来解释就是要将所有的星星聚成k个星团,首先随机选取k个宇宙中的点(或者k个星星)作为k个星团的质心,然后第一步对于每一个星星计算其到k个质心中每一个的距离,然后选取距离最近的那个星团作为,这样经过第一步每一个星星都有了所属的星团;第二步对于每一个星团,重新计算它的质心(对里面所有的星星坐标求平均)。重复迭代第一步和第二步直到质心不变或者变化很小。
下图展示了对n个样本点进行K-means聚类的效果,这里k取2。
K-means面对的第一个问题是如何保证收敛,前面的算法中强调结束条件就是收敛,可以证明的是K-means完全可以保证收敛性。下面我们定性的描述一下收敛性,我们定义畸变函数(distortion function)如下:
J函数表示每个样本点到其质心的距离平方和。K-means是要将J调整到最小。假设当前J没有达到最小值,那么首先可以固定每个类的质心,调整每个样例的所属的类别来让J函数减少,同样,固定,调整每个类的质心也可以使J减小。这两个过程就是内循环中使J单调递减的过程。当J递减到最小时,和c也同时收敛。(在理论上,可以有多组不同的和c值能够使得J取得最小值,但这种现象实际上很少见)。
由于畸变函数J是非凸函数,意味着我们不能保证取得的最小值是全局最小值,也就是说k-means对质心初始位置的选取比较感冒,但一般情况下k-means达到的局部最优已经满足需求。但如果你怕陷入局部最优,那么可以选取不同的初始值跑多遍k-means,然后取其中最小的J对应的和c输出。
下面累述一下K-means与EM的关系,首先回到初始问题,我们目的是将样本分成k个类,其实说白了就是求每个样例x的隐含类别y,然后利用隐含类别将x归类。由于我们事先不知道类别y,那么我们首先可以对每个样例假定一个y吧,但是怎么知道假定的对不对呢?怎么评价假定的好不好呢?我们使用样本的极大似然估计来度量,这里是就是x和y的联合分布P(x,y)了。如果找到的y能够使P(x,y)最大,那么我们找到的y就是样例x的最佳类别了,x顺手就聚类了。但是我们第一次指定的y不一定会让P(x,y)最大,而且P(x,y)还依赖于其他未知参数,当然在给定y的情况下,我们可以调整其他参数让P(x,y)最大。但是调整完参数后,我们发现有更好的y可以指定,那么我们重新指定y,然后再计算P(x,y)最大时的参数,反复迭代直至没有更好的y可以指定。
这个过程有几个难点,第一怎么假定y?是每个样例硬指派一个y还是不同的y有不同的概率,概率如何度量。第二如何估计P(x,y),P(x,y)还可能依赖很多其他参数,如何调整里面的参数让P(x,y)最大。这些问题在以后的篇章里回答。
这里只是指出EM的思想,E步就是估计隐含类别y的期望值,M步调整其他参数使得在给定类别y的情况下,极大似然估计P(x,y)能够达到极大值。然后在其他参数确定的情况下,重新估计y,周而复始,直至收敛。
上面的阐述有点费解,对应于K-means来说就是我们一开始不知道每个样例对应隐含变量也就是最佳类别。最开始可以随便指定一个给它,然后为了让P(x,y)最大(这里是要让J最小),我们求出在给定c情况下,J最小时的(前面提到的其他未知参数),然而此时发现,可以有更好的(质心与样例距离最小的类别)指定给样例,那么得到重新调整,上述过程就开始重复了,直到没有更好的指定。这样从K-means里我们可以看出它其实就是EM的体现,E步是确定隐含类别变量,M步更新其他参数来使J最小化。这里的隐含类别变量指定方法比较特殊,属于硬指定,从k个类别中硬选出一个给样例,而不是对每个类别赋予不同的概率。总体思想还是一个迭代优化过程,有目标函数,也有参数变量,只是多了个隐含变量,确定其他参数估计隐含变量,再确定隐含变量估计其他参数,直至目标函数最优。
又一篇原文的讲解地址:http://www.cnblogs.com/jeromeblog/p/3425919.html
在监督学习中,有标签信息协助机器学习同类样本之间存在的共性,在预测时只需判定给定样本与哪个类别的训练样本最相似即可。在非监督学习中,不再有标签信息的指导,遇到一维或二维数据的划分问题,人用肉眼就很容易完成,可机器就傻眼了,图(1)描述得很形象。
但处理高维度的数据,人脑也无能为力了,最终还是得设计算法让机器来完成。如何将所有样本分成若干个类簇(cluster),并且每个类簇中的样本具有更高的相似度,这就是聚类分析算法的终极目标。这里以最经典的K-means算法为切入点进行说明。 K-means算法的目标是将 m 个样本组成的集合 X={x(1),x(2),⋯,x(m)|x(i)∈Rn} 划分成 k 个类簇( k≤m ),其准则函数形式如下:
算法的内层循环完成两个工作:一是将每个样本划分到与其最近的类簇中心;二是将属于同一个类簇的样本均值作为新的类簇中心。算法的终止条件可以有三种:1)准则函数值的变化小于一个阈值;2)类簇中心在一定范围内不再变化;3)达到指定的迭代次数 T 。K-means的执行步骤如图(2)所示:(a)随机初始化的样本点;(b)随机设置类簇中心;(c)给样本点分配与之最近的类簇中心;(d)类簇中心更新为类簇中所有样本的均值;重复(c)和(d)直到收敛。
这里的准则函数不是凸函数,找到全局最优解是不可能的,但是能保证它收敛到局部最优解,分析如下:
- 更新样本 x(i) 所属的类簇时,总是选择与其最近的类簇中心,所以 ∥x(i)−μ(i)c∥2 在每次迭代过程都是非递增的,那么能保证准则函数 J 也是非递增的;
- 类簇中心被更新为类簇中所有样本的均值也能保证
J
非递增。准则函数对类簇中心求偏导,并令偏导为0即可求得类簇中心的更新规则
∂J∂μj=∂∂μj∑i=1m1{c(i)=j}∥x(i)−μ(i)c∥2=2∑i=1m1{c(i)=j}(μ(i)c−x(i))=0⇒μj=∑mi=11{c(i)=j}x(i)∑mi=11{c(i)=j}(2)
图(3)左侧是在随机生成的四组服从高斯分布的数据上跑完K-means后的聚类结果;右侧则为每次迭代过程中准则函数值的变化曲线图,经过16次迭代后算法就收敛了,这也从实验角度验证了算法的收敛性。因为给定的不同类簇的数据间分得比较开,最后的聚类分析结果堪称完美。由于这次随机初始化的类簇中心情况很糟糕,算法经过16次迭代后才收敛,一般在8次以内就稳定了。
如果样本有多个属性,而且属性不在同一个定义域内,则有必要对样本数据进行预处理,防止某些值很大的属性在计算距离时占主导优势。最常用的就是标准化处理,使得每个属性均值为0,方差为1。 K-means算法对类簇中心的初始化非常敏感,如图(4)所示,我在图中示意性标出了6个可能的初始点,算法会收敛到对应的6个局部最优解,然而只有第2个才是全局最优解。为了避免陷入很差的局部最优解(如第1个局部最优解),常用的策略就是多跑几次K-means,每次都将类簇中心随机初始化,最后选取使准则函数最小的聚类情况。
聚类的最终目的是使同一个类簇中的数据尽可能相似,而不同类簇间的样本彼此离得越远越好。如果我们在初始化类簇中心的时候就遵循这条原则,则可以大大减少收敛所需的迭代次数。下面给出了类簇中心初始化的算法(2)描述,该算法的时间复杂度为 O(m2+km) 。我们可以想象到,该初始化算法实际上是从样本分布的最边缘开始选取类簇中心的,以避免类簇中心被初始化到数据较为密集的地方,大大降低算法收敛需要的迭代次数。有收获必然也要付出代价,这是永恒的真理,这么做是否值还得视情况而定。
在标准的K-means算法中,每个样本点都要和更新后的类簇中心计算距离欧氏距离,如果样本维度较高的话,算法的时间复杂度会非常高。有些大牛们提出用三角不等式或树形结构等对K-means进行加速的算法,以减少不必要的距离计算。建议参考2003年Elkan发表在ICML上的论文《Using the triangle inequality to accelerate k-means》,以及《A generalized optimization of the k-d tree for fast nearest neighbour search》。开源项目VLFeat中就使用了k-d树加速K-means。 在批量版本K-means算法中,我们用所有数据一次性更新类簇中心。但遇到需要在线处理的应用时,处理时间是关键,另外一个挑战就是数据的动态输入,因此有必要为K-means设计一个在线算法。在时间允许的范围内,我们可以一次值处理一条数据,也可以等收集到几条数据后一起处理。在前面证明K-means算法的收敛性过程中,我们求出了准则函数对类簇中心 μj 的偏导,我们很容易将其改造成利用随机梯度下降的online版本算法(3),其中学习率参数 α 应该随处理数据的增多而逐渐减小。
K-means算法的一大特点是每个样本只能被硬性分配(hard assignment)到一个类簇中,这种方法不一定是最合理的。但聚类本身就是一个具有不确定性的问题,如图(5)所示,实际情况中的类簇很可能存在重叠的情况,那么重叠的部分的归属就颇具争议了;给定一个新样本,正好它与所有类簇中心的聚类是相等的,我们又该怎么办?如果我们采用概率的方法,像高斯混合模型(Gauss Mixture Model,GMM)那样给出样本属于每个类簇的概率值,能从一定程度上反映聚类的不确定性就更合理了。
下面介绍K-means算法的两个简单应用:图像分割和数据压缩。图像分割的目标是将图像划分成若个区域,每个区域内有相似的视觉效果。K-means用于图像分割,实际上就是将图像中的所有像素点当成样本点,将相似的像素点尽可能划分到同一个类簇中,最后就形成了 k 个区域,在展示分割情况时以类簇中心代替该类簇中的所有样本。如图(6)所示,我选择了经典的Lena图像和一只小鸟图像进行分割,每次聚类的中心数目 k 从左到右依次为 3,6,12 ,最右侧围原图。Lena图像的颜色种类较少,所有 k=3 时的效果也还行;但是小鸟图像颜色复杂很多,直到 k=12 时图像的分割效果才略微令人满意。图像分割其实是个相当有难度的问题,K-means算法在这个领域还是太弱了...
数据压缩分为无损压缩和有损压缩两大类,无损压缩要求数据还原后要和元素数据一模一样,而有损压缩可以容忍重构数据与元素数据存在一定程度的偏差。K-means算法用于数据压缩只能是有损压缩了, k 越小数据失真越厉害。主要思想是在 N 个样本集合中用于K-means算法得到 k 个类簇中心和 N 个类簇的分配情况,最终我们只需存储类簇中心和每个样本的类簇分配情况即可。假设每个样本的存储空间为 a 字节,则 k 各类簇中心需要的存储空间为 ka 字节,类簇分配情况耗费存储空间为 N⌈log2k⌉ 字节,压缩比为 Na/(ka+N⌈log2k⌉) 。