zoukankan      html  css  js  c++  java
  • K-means Algorithm

    在监督学习中,有标签信息协助机器学习同类样本之间存在的共性,在预测时只需判定给定样本与哪个类别的训练样本最相似即可。在非监督学习中,不再有标签信息的指导,遇到一维或二维数据的划分问题,人用肉眼就很容易完成,可机器就傻眼了,图(1)描述得很形象。

    但处理高维度的数据,人脑也无能为力了,最终还是得设计算法让机器来完成。如何将所有样本分成若干个类簇(cluster),并且每个类簇中的样本具有更高的相似度,这就是聚类分析算法的终极目标。这里以最经典的K-means算法为切入点进行说明。 K-means算法的目标是将(m)个样本组成的集合(X={x^{(1)},x^{(2)},cdots,x^{(m)}|x^{(i)}inmathbb{R}^n})划分成(k)个类簇((kleq m)),其准则函数形式如下: egin{equation} J(c,mu)=sum_{i=1}^m|x^{(i)}-mu_c^{(i)}|^2 end{equation} 其中(c)为样本的类簇分配情况,(mu)为类簇中心点,(mu_c^{(i)})为样本(x^{(i)})对应的类簇中心。准则函数计算的是所有样本点与其对应的类簇中心的距离平方和。使准则函数最小的类簇划分极为最优的聚类。K-means算法描述请下图。

    算法的内层循环完成两个工作:一是将每个样本划分到与其最近的类簇中心;二是将属于同一个类簇的样本均值作为新的类簇中心。算法的终止条件可以有三种:1)准则函数值的变化小于一个阈值;2)类簇中心在一定范围内不再变化;3)达到指定的迭代次数(T)。K-means的执行步骤如图(2)所示:(a)随机初始化的样本点;(b)随机设置类簇中心;(c)给样本点分配与之最近的类簇中心;(d)类簇中心更新为类簇中所有样本的均值;重复(c)和(d)直到收敛。

    这里的准则函数不是凸函数,找到全局最优解是不可能的,但是能保证它收敛到局部最优解,分析如下:

    1. 更新样本(x^{(i)})所属的类簇时,总是选择与其最近的类簇中心,所以(|x^{(i)}-mu_c^{(i)}|^2)在每次迭代过程都是非递增的,那么能保证准则函数(J)也是非递增的;
    2. 类簇中心被更新为类簇中所有样本的均值也能保证(J)非递增。准则函数对类簇中心求偏导,并令偏导为0即可求得类簇中心的更新规则 egin{equation} egin{array}{rl} frac{partial J}{partial mu_j}&=frac{partial}{partialmu_j}sum_{i=1}^m 1{c^{(i)}=j}|x^{(i)}-mu_c^{(i)}|^2\ &=2sum_{i=1}^m 1{c^{(i)}=j}left(mu_c^{(i)}-x^{(i)} ight)=0\ &Rightarrow mu_j=frac{sum_{i=1}^m1{c^{(i)}=j}x^{(i)}}{sum_{i=1}^m1{c^{(i)}=j}} end{array} end{equation}

    图(3)左侧是在随机生成的四组服从高斯分布的数据上跑完K-means后的聚类结果;右侧则为每次迭代过程中准则函数值的变化曲线图,经过16次迭代后算法就收敛了,这也从实验角度验证了算法的收敛性。因为给定的不同类簇的数据间分得比较开,最后的聚类分析结果堪称完美。由于这次随机初始化的类簇中心情况很糟糕,算法经过16次迭代后才收敛,一般在8次以内就稳定了。  

    如果样本有多个属性,而且属性不在同一个定义域内,则有必要对样本数据进行预处理,防止某些值很大的属性在计算距离时占主导优势。最常用的就是标准化处理,使得每个属性均值为0,方差为1。 K-means算法对类簇中心的初始化非常敏感,如图(4)所示,我在图中示意性标出了6个可能的初始点,算法会收敛到对应的6个局部最优解,然而只有第2个才是全局最优解。为了避免陷入很差的局部最优解(如第1个局部最优解),常用的策略就是多跑几次K-means,每次都将类簇中心随机初始化,最后选取使准则函数最小的聚类情况。  

    聚类的最终目的是使同一个类簇中的数据尽可能相似,而不同类簇间的样本彼此离得越远越好。如果我们在初始化类簇中心的时候就遵循这条原则,则可以大大减少收敛所需的迭代次数。下面给出了类簇中心初始化的算法(2)描述,该算法的时间复杂度为(O(m^2+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算法的收敛性过程中,我们求出了准则函数对类簇中心(mu_j)的偏导,我们很容易将其改造成利用随机梯度下降的online版本算法(3),其中学习率参数(alpha)应该随处理数据的增多而逐渐减小。  

    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)字节,类簇分配情况耗费存储空间为(Nlceillog_2 k ceil)字节,压缩比为(Na/left(ka+Nlceillog_2 k ceil ight))。

       

    整个K-means实验的Matlab代码在这里下载!

  • 相关阅读:
    多线程伪共享FalseSharing
    C语言restrict限定符
    Linux线程基础函数
    Linux信号函数
    C函数前向声明省略参数
    12.2 关闭DLM 自动收集统计信息 (SCM0)ORA-00600之[ksliwat: bad wait time]
    pdb的数量限制
    关闭或开启memory_target
    OSWATCH安装
    参数SID写错,ERROR OGG-00664 ORA-01034: ORACLE not available ORA-27101: shared memory realm does not exist
  • 原文地址:https://www.cnblogs.com/jeromeblog/p/3425919.html
Copyright © 2011-2022 走看看