如果说
Spectral Clustering 和传统的聚类方法(例如 K-means)比起来有不少优点:
- 和
K-medoids 类似,Spectral Clustering 只需要数据之间的相似度矩阵就可以了,而不必像 K-means 那样要求数据必须是 N 维欧氏空间中的向量。 - 由于抓住了主要矛盾,忽略了次要的东西,因此比传统的聚类算法更加健壮一些,对于不规则的误差数据不是那么敏感,而且 performance 也要好一些。许多实验都证明了这一点。事实上,在各种现代聚类算法的比较中,K-means 通常都是作为 baseline 而存在的。
- 计算复杂度比 K-means 要小,特别是在像文本数据或者平凡的图像数据这样维度非常高的数据上运行的时候。
突然冒出这么一个要求比 K-means 要少,结果比 K-means 要好,算得还比 K-means 快的东西,实在是让人不得不怀疑是不是江湖骗子啊。所以,是骡子是马,先拉出来溜溜再说。不过,在K-medoids
结果来自论文
k | TDT2 | Reuters-21578 | ||
K-means | SC | K-means | SC | |
2 | 0.989 | 0.998 | 0.871 | 0.923 |
3 | 0.974 | 0.996 | 0.775 | 0.816 |
4 | 0.959 | 0.996 | 0.732 | 0.793 |
… | ||||
9 | 0.852 | 0.984 | 0.553 | 0.625 |
10 | 0.835 | 0.979 | 0.545 | 0.615 |
其中 TDT2 和 Reuters-21578 分别是两个被广泛使用的标准文本数据集,虽然在不同的数据集上得出来的结果并不能直接拿来比较,但是在同一数据集上 K-means 和 SC (Spectral Clustering) 的结果对比就一目了然了。实验中分别抽取了这两个数据集中若干个类别(从 2 类到 10 类)的数据进行聚类,得出的 accuracy 分别在上表中列出(我偷懒没有全部列出来)。可以看到,Spectral Clustering 这里完胜 K-means 。
这么强大的算法,再戴上“谱聚类”这么一个高深莫测的名号,若不是模型无比复杂、包罗宇宙,就肯定是某镇山之宝、不传秘籍吧?其实不是这样,Spectral Clustering 不管从模型上还是从实现上都并不复杂,只需要能求矩阵的特征值和特征向量即可──而这是一个非常基本的运算,任何一个号称提供线性代数运算支持的库都理应有这样的功能。而关于 Spectral Clustering 的秘籍更是满街都是,随便从地摊上找来一本,翻开便可以看到 Spectral Clustering 算法的全貌:
- 根据数据构造一个 Graph ,Graph 的每一个节点对应一个数据点,将相似的点连接起来,并且边的权重用于表示数据之间的相似度。把这个 Graph 用邻接矩阵的形式表示出来,记为
。一个最偷懒的办法就是:直接用我们前面在 K-medoids 中用的相似度矩阵作为 。 - 把
的每一列元素加起来得到 个数,把它们放在对角线上(其他地方都是零),组成一个 的矩阵,记为 。并令 。 - 求出
的前 个特征值(在本文中,除非特殊说明,否则“前 个”指按照特征值的大小从小到大的顺序) 以及对应的特征向量 。 - 把这
个特征(列)向量排列在一起组成一个 的矩阵,将其中每一行看作 维空间中的一个向量,并使用 K-means 算法进行聚类。聚类的结果中每一行所属的类别就是原来 Graph 中的节点亦即最初的 个数据点分别所属的类别。
就是这么几步,把数据做了一些诡异的变换,然后还在背后偷偷地调用了 K-means 。到此为止,你已经可以拿着它上街去招摇撞骗了。不过,如果你还是觉得不太靠谱的话,不妨再接着往下看,我们再来聊一聊 Spectral Clustering 那几个“诡异变换”背后的道理何在。
其实,如果你熟悉
在 Image Processing (我好像之前有听说我对这个领域深恶痛绝?)里有一个问题就是对图像进行
另一方面,还有一个经常被研究的问题就是
实际上,抛开图像分割的问题不谈,在 Graph Cut 相关的一系列问题中,Minimum cut (最小割)本身就是一个被广泛研究的问题,并且有成熟的算法来求解。只是单纯的最小割在这里通常并不是特别适用,很多时候只是简单地把和其他像素联系最弱 的那一个像素给分割出去了,相反,我们通常更希望分割出来的区域(的大小)要相对均匀一些,而不是一些很大的区块和一些几乎是孤立的点。为此,又有许多替 代的算法提出来,如 Ratio Cut 、Normalized Cut 等。
不过,在继续讨论之前,我们还是先来定义一下符号,因为仅凭文字还是很难表述清楚。将 Graph 表示为邻接矩阵的形式,记为 ,其中
先考虑最简单的情况,如果把一个 Graph 分割为两个部分的话,那么 Minimum cut 就是要最小化
以及 NormalizedCut :
其中
搬出 RatioCut 和 NormalizedCut 是因为它们和这里的 Spectral Clustering 实际上有非常紧密的联系。看看 RatioCut ,式子虽然简单,但是要最小化它却是一个 NP 难问题,不方便求解,为了找到解决办法,让我们先来做做变形。
令
:
再回忆一下我们最开始定义的矩阵
Usually, every author just calls “his” matrix the graph Laplacian.
其实也可以理解,就好象现在所有的厂家都说自己的技术是“云计算”一样。这个
这个是对任意向量
另外,如果令
问题转化到这个样子就好求了,因为有一个叫做
他的最大值和最小值分别等于矩阵
等于对应的特征向量时取到。由于
到这一步,我们看起来好像是很容易地解决了前面那个 NP 难问题,实际上是我们耍了一个把戏:之前的问题之所以 NP 难是因为向量
到此为止,已经有 Spectral Clustering 的影子了:求特征值,再对特征向量进行 K-means 聚类。实际上,从两类的问题推广到 k 类的问题(数学推导我就不再详细写了),我们就得到了和之前的 Spectral Clustering 一模一样的步骤:求特征值并取前 k 个最小的,将对应的特征向量排列起来,再按行进行 K-means 聚类。分毫不差!
用类似的办法,NormalizedCut 也可以等价到 Spectral Clustering 不过这次我就不再讲那么多了,感兴趣的话(还包括其他一些形式的 Graph Laplacian 以及 Spectral Clustering 和
为了缓和一下气氛,我决定贴一下 Spectral Clustering 的一个简单的 Matlab 实现:
function idx = spectral_clustering(W, k) D = diag(sum(W)); L = D-W;opt = struct('issym', true, 'isreal', true); [V dummy] = eigs(L, D, k, 'SM', opt); idx = kmeans(V, k); end
最后,我们再来看一下本文一开始说的 Spectral Clustering 的几个优点:
- 只需要数据的相似度矩阵就可以了。这个是显然的,因为 Spectral Clustering 所需要的所有信息都包含在
中。不过一般 并不总是等于最初的相似度矩阵——回忆一下, 是我们构造出来的 Graph 的邻接矩阵表示,通常我们在构造 Graph 的时候为了方便进行聚类,更加强到“局部”的连通性,亦即主要考虑把相似的点连接在一起,比如,我们设置一个阈值,如果两个点的相似度小于这个阈值,就把他们看作是不连接的。另一种构造 Graph 的方法是将 n 个与节点最相似的点与其连接起来。
- 抓住了主要矛盾,忽略了次要的东西,Performance 比传统的 K-means 要好。实际上 Spectral Clustering 是在用特征向量的元素来表示原来的数据,并在这种“更好的表示形式”上进行 K-means 。实际上这种“更好的表示形式”是用 Laplacian Eigenmap 进行降维的后的结果,如果有机会,下次谈 Dimensionality Reduction 的时候会详细讲到。而降维的目的正是“抓住主要矛盾,忽略次要的东西”。
- 计算复杂度比 K-means 要小。这个在高维数据上表现尤为明显。例如文本数据,通常排列起来是维度非常高(比如,几千或者几万)的稀疏矩阵,对稀疏矩阵求特征值和特征向量有很高效的办法,得到的结果是一些 k 维的向量(通常 k 不会很大),在这些低维的数据上做 K-means 运算量非常小。但是对于原始数据直接做 K-means 的话,虽然最初的数据是稀疏矩阵,但是 K-means 中有一个求 Centroid 的运算,就是求一个平均值:许多稀疏的向量的平均值求出来并不一定还是稀疏向量,事实上,在文本数据里,很多情况下求出来的 Centroid 向量是非常稠密,这时再计算向量之间的距离的时候,运算量就变得非常大,直接导致普通的 K-means 巨慢无比,而 Spectral Clustering 等工序更多的算法则迅速得多的结果。
说了这么多,好像有些乱,不过也只能到此打住了。最后再多嘴一句,Spectral Clustering 名字来源于
UPDATE 2011.11.23: 有不少同学问我关于代码的问题,这里更新两点主要的问题:
- 关于 LE 降维的维度和 Kmeans 聚类的类别数的关系:我上面的代码里,取成了一样的,但是这两者并不是要求一定要一样的。最初 Spectral Cluster 是分析聚两类的情况,就降到 1 维,然后用 thresholding 的方法来分成两类。对于K 类的情况,自然的类比就是降到 K-1 维,这也是和
LDA 保持一致。因为 Laplacian 矩阵的特征向量有一个全一的向量(对应于特征值 0 ),所以可以求 K 个特征向量然后把特征值 0 对应的那个特征向量去掉。但是在实际中并不一定要保持这两者一致的,也就是说,这个降维的维度可以作为一个参数进行调节的,选择效果好的参数。 - 关于示例代码:注意除非我在这里注明了是发布某个 software 或者 package 什么的,否则这里贴的代码主要都是为了示例作用,为了只显示出算法的主要部分,因此通常会省略掉一些实现细节,可以看成是“可执行的伪代码”,不推荐直接用这里的代码去跑实验之类的(包括其他 post 里的相关代码)。除非你想自己试验一下具体实现和改进,否则可以直接找网上现成的专用的 package ,比如 Spectral Clustering 可以考虑这个包。
本文转载自:pluskid