聚类分析是非监督学习的很重要的领域。所谓非监督学习,就是数据是没有类别标记的,算法要从对原始数据的探索中提取出一定的规律。而聚类分析就是试图将数据集中的样本划分为若干个不相交的子集,每个子集称为一个“簇”。下面是sklearn中对各种聚类算法的比较。
KMeans算法在给定一个数k之后,能够将数据集分成k个“簇” C={C1,C2,⋯,Ck} ,不论这种分类是否合理,或者是否有意义。算法需要最小化平方误差:
当p==2的时候,闵可夫斯基距离即为欧氏距离(2范数)
当p==1的时候,闵可夫斯基距离即为曼哈顿距离(1范数 或者叫 cityblock distance)
以上是对于数值属性来说的,对于一些离散属性也有相关的距离的定义。最后在现实中的数据如果要确定合适的距离计算式,可以通过“距离度量学习”来实现。
也就是说上面的式(1)的目的就是我们要找到k个簇,使得在每个簇内,所有的样本点都尽量靠得比较近。
下面介绍KMeans的基本算法流程
输入:样本数据集 D ,聚类簇数k
(1) 从样本中随机选取k个样本点作为初始的均值向量 {μ1,μ2,⋯,μk}
(2)循环以下几步直到达到停止条件:
(2.1)令 Ci=∅(1≤i≤k)
(2.2)对所有样本点计算他们到k个均值向量之间的距离,取其中距离最短的距离对应的均值向量的标记作为该点的簇标记,然后将该点加入相应的簇 Ci
(2.3)对每一个簇计算他们新的均值向量 μi=1|Ci|∑x∈Cix ,如果相比之前的向量有变化,就更新,将其作为新的均值向量,如果没有变化就不变
可以看出KMeans的基本算法是很容易理解的,算法本身也挺简单,运行较快,所以KMeans可用于非常大型的数据集。但是KMeans也有一些缺点
(1)对初始值敏感。KMeans可能由于初始值选的不同,导致最终结果的不同。我的理解是我们要优化的其实是式(1),但是它很难优化,所以我们采用的是一种贪心算法,那么这种算法就可能掉进局部最优的坑里面,所以我们要尽量多选几个初始值多计算几次。不过scikit-learn里面KMeans的算法的参数里面有个’init’参数,将其设置成’init = k-means++’可以在初始化均值向量的时候让他们之间尽量分开。
(2)对特殊分布的数据集不能够得出合理的结果
比如上图,我们希望的结果应该是左图,但是KMeans只能得出右图,不能得出我们想要的结果,但是这不是KMeans单独的缺点,很多聚类算法对这种情况或者数据分布是一种长条形等的一类特殊情况效果都不甚理想。这些情况在文章开头的图中都有所体现。
总体上KMeans以及它很多聚类算法对于每一簇数据分布都是凸的情况效果都很好。
除了KMeans之外,我们还有一些它的变体的算法比如 Mini Batch K-means 或者Learning Vector Quantization (LVQ)等,在这里就不再赘述。
密度聚类的思想是不同于KMeans的,但是更符合我们人类的思维,基本的思想是通过是否紧密相连来判断样本点是否属于一个簇。代表性的算法就是DBSCAN,它基于一组邻域参数 (ϵ,MinPts) 来表征某处样本是否是紧密的。在介绍算法之前先介绍一些概念。
ϵ -邻域:即对于样本点 xi ,和它的距离在 ϵ 之内的属于样本集 D 中的点的集合,即 Nϵ(xj)={si∈D|dist(xi,xj)≤ϵ}
核心对象:若 xj 的 ϵ -邻域至少包含 MinPts 个样本,即 |Nϵ(xj)|≥MinPts ,那么 xj 是一个核心对象。其实也就是在核心对象周围的点相对邻域参数来说是致密的。
密度直达与可达:直达的意思是点 xj 位于点 xi 的 ϵ -邻域中。可达的意思是存在这么一个样本序列 p1,p2,⋯,pn , xj 到 p1 是直达的, p1 到 p2 是直达的,就这样不断地借着这些样本作为“跳板”, xj 可以间接地“跳到” xi 。
密度相连:对于样本点 xj 和 xi 若存在点 xk 使得 xj 和 xi 均可由 xk 密度可达,则称 xj 和 xi 密度相连。
最后由DBSCAN所定义的簇的概念为:由密度可达关系导出的最大的密度相连样本集合。
下图为DBSCAN的一个结果示意图
如图算法自动将数据集分成了3簇,用三种颜色代表。每一簇内较大的点代表核心对象,较小的点代表边界点(与簇内其他点密度相连,但是自身不是核心对象)。黑色的点代表离群点或者叫噪声点。
另外从最上面的图也能够看出DBSCAN的表现还是很不错的。
其实周志华老师的书《机器学习》上对算法的描述更清晰,感兴趣的可以去看看。
这里提一个我的想法,我在看算法的时候就觉得这个算法有点眼熟,后来想起来发现跟广度优先搜索有点像,再想想发现DBSCAN的思路就是和广度优先很想。比如密度直连的两个点之间可以看作这两个点相连,密度可达可以看作两个点之间存在一条路径,找出所有的簇就可以看作找出整个图中的连通分量。另外在数据结构上DBSCAN和广度优先都使用了队列来储存访问到的点。只是由 (ϵ,MinPts) 来确定两个点是否相连。以上提供一个视角以供参考。
DBSCAN的优点:
(1)可以解决数据分布特殊(非凸, 互相包络,长条形等)的情况
(2)对于噪声不敏感
(3)速度较快,可适用于较大的数据集
(4)在邻域参数 (ϵ,MinPts) 给定的情况下,结果是确定的,只要数据进入算法的顺序不变,与初始值无关,这里就和KMeans不同
(5)不需要指定簇的个数
缺点:
(1)簇之间密度差距过大时效果不好,因为对整个数据集我们使用的是一组邻域参数
(2)数据集较大的时候很消耗内存,目前在scikit-learn中已经可以使用ball-trees 和 kd-trees来确定邻居点(可以看出找出点的邻域内有几个点是DBSCAN最基本,最多的操作),但是在默认情况下是不使用他们的,而是使用很消耗内存的距离矩阵。
(3)对于高维数据距离的计算会比较麻烦,造成“维数灾难”
层次聚类是一类算法的总称,是通过从下往上不断合并簇,或者从上往下不断分离簇形成嵌套的簇。这种层次的类通过“树状图”来表示。AgglomerativeClustering算法是一种层次聚类的算法。
下面大致讲一下 AgglomerativeClustering算法。
算法的原理很简单,最开始的时候将所有数据点本身作为簇,然后找出距离最近的两个簇将它们合为一个,不断重复以上步骤直到达到预设的簇的个数。
可以看到,一个很关键的地方就是判断簇之间的距离。判断的准则叫做链接准则。对于AgglomerativeClustering算法,scikit-learn有三种准则
• Ward minimizes the sum of squared differences within all clusters. It is a variance-minimizing approach and in
this sense is similar to the k-means objective function but tackled with an agglomerative hierarchical approach.
• Maximum or complete linkage minimizes the maximum distance between observations of pairs of clusters.
• Average linkage minimizes the average of the distances between all observations of pairs of clusters.
三种准则有所不同,在后面的文章中再来探讨他们的区别
AgglomerativeClustering也是适用于较大的数据集的,尤其是在有connectivity constraint的时候,什么是connectivity constraint?下面有一个图
左边是没有connectivity constraint的,可以看到有些蓝色的簇横跨了两片(只能这么表述了),右边有connectivity constraint的情况下,簇可以看到基本就是沿着弯曲的平面分布的,这种结果可能更合理,并且是可以加快计算速度的,尤其是在数据量很大的情况下。因为对于每个点只需要考虑和它相邻的点,而不是考虑所有的点。但是connectivity constraint需要一个叫做connectivity matrix的东西,这个矩阵我也不清楚具体形式,写这些只是提醒有connectivity constraint这么个东西存在。
还有,从最上方的图中也能够看出AgglomerativeClustering算法对于形状比较怪异的分布也有较好的效果
综上就是我挑出的三个主要的聚类算法进行了大致的介绍,另外还有一个算法:高斯混合模型,我准备把它和EM算法一起单独写篇文章。聚类算法可以作为一些监督算法的前驱过程,又是非监督学习的重要部分,还是很重要的。
参考:
DBSCAN聚类原理
DBSCAN密度聚类算法