简单算法复杂说-Kmeans

前言

先看一个简单的例子

有四个牧师去郊区布道,一开始牧师们随意选了几个布道点,并且把这几个布道点的情况公告给了郊区所有的居民,于是每个居民到离自己家最近的布道点去听课。
听课之后,大家觉得距离太远了,于是每个牧师统计了一下自己的课上所有的居民的地址,搬到了所有地址的中心地带,并且在海报上更新了自己的布道点的位置。
牧师每一次移动不可能离所有人都更近,有的人发现A牧师移动以后自己还不如去B牧师处听课更近,于是每个居民又去了离自己最近的布道点……
就这样,牧师每个礼拜更新自己的位置,居民根据自己的情况选择布道点,最终稳定了下来。

在机器学习中,例子中居民就是我们的样本点,四个牧师就是我们的聚类的中心点。这里分成几个步骤
  1.随机挑选聚类中心(四个牧师随意选了几个布道点)
  2.样本归类到最近的中心点所属的类别中(居民到离自己最近的布道点听课)
  3.每个类别重新计算中心点(牧师重新选择布道位置)
  4.重复2,3步骤,直至收敛(牧师稳定下来了)
以上就是我们Kmeans算法的大致迭代过程。简单高效神奇

用一个图来更好描述这样一个过程

实践中,我们只需要选定K值和初始中心点,其他的直接交给计算机了。
值得思考的是,我们选定了K值,聚过程中会不会出现类别个数小于K呢?更直观地说,四个牧师会不会就剩三个了?

一.原理

和其他算法模型一样,kmeans也自己的**损失函数**(目标函数) 设有K个cluster为

( C 1 , C 2 , . . . C k ) (C_1,C_2,...C_k) (C1,C2,...Ck),目标就是最小化所有样本点到各自cluster的距离之和SSE(sum of the squared errors 误差平方和)
E = ∑ i = 1 k ∑ x ∈ C i ∣ ∣ x − μ i ∣ ∣ 2 2 E = \sum\limits_{i=1}^k\sum\limits_{x \in C_i} ||x-\mu_i||_2^2 E=i=1kxCixμi22
其中 μ i \mu_i μi C i C_i Ci的质心,表达式为:
μ i = 1 ∣ C i ∣ ∑ x ∈ C i x \mu_i = \frac{1}{|C_i|}\sum\limits_{x \in C_i}x μi=Ci1xCix
这里的可观测数据是样本点和聚类的隶属关系(通过计算样本点与各个中心点的距离求得)
但是存在一个隐变量:聚类中心点在哪里?

隐变量的优化问题梯度下降没法解决,EM算法可以!

用EM算法来解决这样一个问题的思路就是:
根据现有的隐含变量,计算各个样本点的分类结果称为期望值计算过程,E step
接下来,重新计算隐含变量称为最大化过程,M step

更多Kmeans的数学推导可自行Google,与EM的关系可参考**“数学之美 第二版”**242页

Q:通过EM算法迭代的Kmeans能保证全局最优解吗?
A:本身是凸优化问题,由欧氏距离构造的目标函数是凸函数,只要数据是凸集,能得到全局最优解

二.如何初始化中心点

EM算法的诟病就是初始值敏感,Kmeans当然也是。不同的初始值会得到不同的结果,对算法的收敛时间也会有很大影响。 一般kmeans初始化有三种方法: a)手动指定 b)随机 c)kmeans++

实际应用中通常采用kmeans++,它的策略也很简单的,如下:
1.从样本点中随机选一个作为第一个聚类中心 μ 1 \mu_1 μ1
2.计算每个样本与当前已有的聚类中心的最短距离 D ( x ) D(x) D(x)
3.以一定的概率挑选下一个中心点,原则是 D ( x ) D(x) D(x)越大,概率越小。
4.重复2,3 直到挑选出K个中心点。

通过Kmeans++初始化的中心点,在数据中比较分散,但也不会绝对地分布在数据的边缘。

sklearn默认的初始方式就是kmeans++
同时它会默认多次选取初始值进行聚类,把效果最好的返回给用户,这也是解决初始值敏感常用的一种方法。

三.如何选取K值

1.经验判定
根据数据的先验知识决定K值范围,肉眼观测聚类效果,选取效果最好的K值。K值如果较大时,这个方法就不适用了。
2.手肘法
计算聚类后**目标函数SSE**的值。随着K的增加,样本划分的越细,SSE自然会越小。极端情况下K取样本数,SSE为0。 当K未到达真实值时,SSE下降的幅度会很大,到达真实值后,K再增加SSE的下降幅度就会变小趋于平缓。SSE和K的关系图像像一个手肘的形状,如下图。而这个肘部对应的K值就作为最优的K值。
3.轮廓系数
计算轮廓系数,越小K值越佳
4.小结
K值是Kmeans最重要也是最难决定的参数,K值过小导致模型欠拟合,K值过大导致模型过拟合。 合理地选择K值是Kmeans工程实践中最重要的工作。

四.计算加速

1.elkan Kmeans
如果有m个样本点,样本点的维度是n,cluster数目为k,迭代t次。整个算法的时间复杂度为$O=m*n*k*t$当样本点很多,维度很大时候,这种全比较计算复杂度还是很高的。距离计算上能否做到简化?elkan Kmeans就是从这方面改进的。它的目标就是减少不必要的计算。

第一种规律是对于一个样本点 x x x和两个质心 μ j 1 , μ j 2 \mu_{j_1}, \mu_{j_2} μj1,μj2。如果我们预先计算出了这两个质心之间的距离 D ( j 1 , j 2 ) D(j_1,j_2) D(j1,j2),则如果计算发现 2 D ( x , j 1 ) ≤ D ( j 1 , j 2 ) 2D(x,j_1) \leq D(j_1,j_2) 2D(x,j1)D(j1,j2),我们立即就可以知道 D ( x , j 1 ) ≤ D ( x , j 2 ) D(x,j_1) \leq D(x, j_2) D(x,j1)D(x,j2)。此时我们不需要再计算 D ( x , j 2 ) D(x, j_2) D(x,j2),也就是说省了一步距离计算。

第二种规律是对于一个样本点x和两个质心 μ j 1 , μ j 2 \mu_{j_1}, \mu_{j_2} μj1,μj2。我们可以得到 D ( x , j 2 ) ≥ m a x { 0 , D ( x , j 1 ) − D ( j 1 , j 2 ) } D(x,j_2) \geq max\{0, D(x,j_1) - D(j_1,j_2)\} D(x,j2)max{0,D(x,j1)D(j1,j2)}。这个从三角形的性质也很容易得到

elkan Kmeans 巧妙地利用两边之和大于第三边,以及两边之差小于第三边的三角性质,来减少不必要的计算。

elkan Kmeans比传统的Kmeans迭代速度有很大的提高。sklearn在检测我们的样本数据的特征是非稀疏时候,默认使用该方法加速

2.转内积计算
如果样本维度很高的时候,单个样本和cluster中心点计算距离就很耗时。处理这种问题通常是将高维下的欧式距离计算转化成计算内积的方式。 $$||x-c||^2=
3.小结
上面提到的两种加速方法都可以在sklearn中找到对应的实现。当我们的样本是高维稀疏的时候,使用第2种方法。样本非稀疏时候,使用了第1种方法。当然我们可以同时采用这两种方法,毕竟两种技巧从不同方面提出来的。

五.大数据下的Kmeans

1.min-batch Kmeans
神经网络在迭代更新参数时,每个Epoch下最理想的做法是在整个样本集上一次性计算梯度值,然后再更新参数。在样本数据很多时,这种方法会极慢并且out memory,所以提出了mini-batch的方法,每次随机地挑选出batch size个样本数据来更新参数。牺牲了一点精度的情况下加快了速度。

传统的Kmeans即使有上面提到的加速方法,但在数据量达到百万级以上时仍旧很慢。于是有了mini-batch Kmeans
mini-batch Kmeans采用类似神经网络mini-batch的方法。我们会选择一个batch size,仅仅用batch size个样本做Kmeans训练,这里的batch size个样本一般通过无放回的随机采样得到。
为了增加精度,一般会跑几次mini batch Kmeans,用不同的采样集得到聚类结果,选取其中最优的cluster,这里最优的判定方法依赖SSE

2.并行化
Kmeans绝大部分计算用在E step上,而E step是很容易实现分布式计算的。 基于map-reduce的Kmeans算法流程大致如下: a)初始化k个中心点 b)将中心点broadcast到各个节点 c)map过程:各个节点上的样本点计算与中心点的距离,得到新的类别,同类的样本可以做向量求和操作 d)reduce过程:以类别为key,同类别的求和结果会reduce在一块,本地对节点的向量和结果再次按照类别求和,结果除以各类别的个数得到新的中心点 e)重复b,c,d直至收敛

更多细节可参见 Spark Kmeans实现.

六.实验

选取实际资讯推荐项目中1000条新闻数据(仅科技类)进行聚类。在简单清洗,切词后如下

新闻中包括了互联网,各类手机品牌,电脑硬件,天文宇宙等不同主题的资讯。主题的个数是未知的。

使用kmeans聚类之前,先通过tf-idf对文本进行编码。每条新闻转换成 ∣ V ∣ |V| V维的向量, ∣ V ∣ |V| V为语料的词表大小,实验中约2万+

这里有个细节,通过tf-idf编码得到的vector要进行L2 Norm,文本相似我们通常用cosine距离来衡量,标准的Kmeans是基于欧式距离的。经过L2 Norm处理后的vector,计算cosine距离和欧式距离等价。

选取不同的K值绘制出K-SSE图

上图最明显的两个手肘点出现在K等于14,22

实验中的数据量并不是很大,但绘制这样一个曲线图个人PC上还是花费数小时。
实际项目中,数据量较大时,我们可以采用上文提到的mini-batch Kmeans帮我们绘制这样的曲线图

考虑到K=22会产生过拟合,选取14作为K值

K=14部分聚类效果如下

可以看出不同品牌的手机资讯聚类在一起,iPhone,vivo,OPPO,小米,魅族等,天文宇宙资讯聚在一起。

七.总结及补充

1)K值是Kmeans中最重要的参数,可以通过手肘法来估计,数据量很大时用mini-batch Kmeans来绘制k-SSE图。
2)对初始值敏感,kmeans++可以缓和初始值的影响。
3)通过elkan Kmeans和转内积法加速计算,sklearn和spark的Kmeans都集成这两种方法,只需要愉快调包:)
4)对噪音异常数据敏感。Kmeans是hard-assign模型,处理异常数据效果不佳。这时候可采用混合高斯模型等。
5)由于是EM算法,对于非凸数据集速度慢,难收敛。
6)由于是基于欧式距离的聚类的,只能发现球形类簇。
7)基于其他距离衍生出一些K算法,如Spherical k-means,Kmedoids,Kmedian,Kcenter
它们有各自的应用场景,但是不太常用,我也没深究。

八.TO DO

后面有时间与其他聚类算法做详细对比
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值