有四个牧师去郊区布道,一开始牧师们随意选了几个布道点,并且把这几个布道点的情况公告给了郊区所有的居民,于是每个居民到离自己家最近的布道点去听课。
听课之后,大家觉得距离太远了,于是每个牧师统计了一下自己的课上所有的居民的地址,搬到了所有地址的中心地带,并且在海报上更新了自己的布道点的位置。
牧师每一次移动不可能离所有人都更近,有的人发现A牧师移动以后自己还不如去B牧师处听课更近,于是每个居民又去了离自己最近的布道点……
就这样,牧师每个礼拜更新自己的位置,居民根据自己的情况选择布道点,最终稳定了下来。
在机器学习中,例子中居民就是我们的样本点,四个牧师就是我们的聚类的中心点。这里分成几个步骤
1.随机挑选聚类中心(四个牧师随意选了几个布道点)
2.样本归类到最近的中心点所属的类别中(居民到离自己最近的布道点听课)
3.每个类别重新计算中心点(牧师重新选择布道位置)
4.重复2,3步骤,直至收敛(牧师稳定下来了)
以上就是我们Kmeans算法的大致迭代过程。简单,高效又神奇!
用一个图来更好描述这样一个过程
实践中,我们只需要选定K值和初始中心点,其他的直接交给计算机了。
值得思考的是,我们选定了K值,聚过程中会不会出现类别个数小于K呢?更直观地说,四个牧师会不会就剩三个了?
( 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=1∑kx∈Ci∑∣∣x−μi∣∣22
其中 μ 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=∣Ci∣1x∈Ci∑x
这里的可观测数据是样本点和聚类的隶属关系(通过计算样本点与各个中心点的距离求得)
但是存在一个隐变量:聚类中心点在哪里?
含隐变量的优化问题梯度下降没法解决,EM算法可以!
用EM算法来解决这样一个问题的思路就是:
根据现有的隐含变量,计算各个样本点的分类结果称为期望值计算过程,E step
接下来,重新计算隐含变量称为最大化过程,M step
更多Kmeans的数学推导可自行Google,与EM的关系可参考**“数学之美 第二版”**242页
Q:通过EM算法迭代的Kmeans能保证全局最优解吗?
A:本身是凸优化问题,由欧氏距离构造的目标函数是凸函数,只要数据是凸集,能得到全局最优解
实际应用中通常采用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++
同时它会默认多次选取初始值进行聚类,把效果最好的返回给用户,这也是解决初始值敏感常用的一种方法。
第一种规律是对于一个样本点 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在检测我们的样本数据的特征是非稀疏时候,默认使用该方法加速
传统的Kmeans即使有上面提到的加速方法,但在数据量达到百万级以上时仍旧很慢。于是有了mini-batch Kmeans
mini-batch Kmeans采用类似神经网络mini-batch的方法。我们会选择一个batch size,仅仅用batch size个样本做Kmeans训练,这里的batch size个样本一般通过无放回的随机采样得到。
为了增加精度,一般会跑几次mini batch Kmeans,用不同的采样集得到聚类结果,选取其中最优的cluster,这里最优的判定方法依赖SSE
更多细节可参见 Spark Kmeans实现.
新闻中包括了互联网,各类手机品牌,电脑硬件,天文宇宙等不同主题的资讯。主题的个数是未知的。
使用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
它们有各自的应用场景,但是不太常用,我也没深究。