谱聚类

1. 基本原理

它的主要思想:把所有数据看成空间中的点,这些点之间可以用变连接起来,距离较远的两个点之间的边权重较低,而距离较近的两个点之间的权重较高,通过对所有数据点组成的图进行切图,让切图后的不同的子图间边权重和尽可能小(即距离远),而子图内的边权重和尽可能高(即距离近)。

难点:

  1. 如何构建图?
  2. 如何切分图?

2. 谱聚类基础

2.1 无向权重图

对于一个图试用谱聚类算法进行聚类分 析_无向权重图,我们一般用点集合试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_02和边集合试用谱聚类算法进行聚类分 析_图切分_03来描述,即试用谱聚类算法进行聚类分 析_谱聚类_04。我们定义权重试用谱聚类算法进行聚类分 析_图切分_05为点试用谱聚类算法进行聚类分 析_谱聚类_06之间的权重,由于是无向图,故试用谱聚类算法进行聚类分 析_图切分_07

对于有边连接的两个点试用谱聚类算法进行聚类分 析_谱聚类_08试用谱聚类算法进行聚类分 析_图切分_09;对于没有边连接的两个点试用谱聚类算法进行聚类分 析_谱聚类_08试用谱聚类算法进行聚类分 析_图切分_11

对于图中的任意一个点试用谱聚类算法进行聚类分 析_无向权重图_12,它的度试用谱聚类算法进行聚类分 析_谱聚类_13定义为和它相连的所有边权重之和,即
试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_14

利用每个点度的定义,我们可以得到一个试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_15的度矩阵试用谱聚类算法进行聚类分 析_图切分_16,它是一个对角阵,只有主对角有值,对应第试用谱聚类算法进行聚类分 析_谱聚类_17行为第试用谱聚类算法进行聚类分 析_谱聚类_17个点的度;利用所有点之间的权重,我们可以得到图的邻接矩阵试用谱聚类算法进行聚类分 析_图切分_19,它也是一个试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_15矩阵,第试用谱聚类算法进行聚类分 析_谱聚类_17行的第试用谱聚类算法进行聚类分 析_谱聚类_22个值对应权重试用谱聚类算法进行聚类分 析_图切分_05

除此之外,对于点集试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_24的一个子集试用谱聚类算法进行聚类分 析_无向权重图_25,我们定义:
试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_26

2.2 拉普拉斯矩阵

拉普拉斯矩阵试用谱聚类算法进行聚类分 析_图切分_27,其性质如下:

  1. 对称矩阵,由于试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_28都为对称矩阵
  2. 由于是对称矩阵,它的所有特征值都是实数
  3. 对于任意向量试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_29,有
    试用谱聚类算法进行聚类分 析_无向权重图_30
  4. 由于拉普拉斯矩阵是半正定的,其对应的试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_31个特征值都大于等于0。

3. 构建图——构建邻接矩阵

3.1 试用谱聚类算法进行聚类分 析_图切分_32邻近法

通过设置一个阈值试用谱聚类算法进行聚类分 析_图切分_32,然后利用欧氏距离试用谱聚类算法进行聚类分 析_图切分_34度量任意两点试用谱聚类算法进行聚类分 析_谱聚类_08的距离,即试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_36,然后根据试用谱聚类算法进行聚类分 析_无向权重图_37的大小关系,来定义邻接矩阵试用谱聚类算法进行聚类分 析_图切分_19
试用谱聚类算法进行聚类分 析_无向权重图_39

从上式可知,两点间的权重要么试用谱聚类算法进行聚类分 析_图切分_32,要么0,就没有其他信息了,距离远近度量很不明确,因此在实际应用中,很少采用。

3.2 试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_41近邻法

利用KNN算法遍历所有的样本点,取每个样本最近的试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_41个点作为近邻,只有和样本距离最近的试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_41个点之间的试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_44。但是这种方法会造成重构之后的邻接矩阵试用谱聚类算法进行聚类分 析_图切分_19非对称,我们后面的算法需要邻接矩阵对称。为了解决这种问题,一般采取下面两种方法之一:

  1. 只要一个点在另一个点的K近邻中,就保留试用谱聚类算法进行聚类分 析_图切分_46
    试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_47
  2. 必须两个点互为试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_48近邻中,才能保留试用谱聚类算法进行聚类分 析_图切分_46
    试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_50

3.3 全连接法

比前两种方法,第三种方法所有的点之间的权重值都大于0,因此称之为全连接法。可以选择不同的核函数来定义边权重,常用的有多项式核函数,高斯核函数和Sigmoid核函数。最常用的是高斯核函数RBF试用谱聚类算法进行聚类分 析_无向权重图_51

在实际的应用中,使用第三种全连接法来建立邻接矩阵是最普遍的,而在全连接法中使用高斯径向核RBF是最普遍的。

4. 图的切分

对于无向图试用谱聚类算法进行聚类分 析_无向权重图的切分,我们的目标是将图试用谱聚类算法进行聚类分 析_无向权重图_53切成相互没有连接的试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_41个子图,每个子图集合为:试用谱聚类算法进行聚类分 析_图切分_55,它们满足试用谱聚类算法进行聚类分 析_图切分_56

对于任意两个子图点的集合试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_57,我们定义试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_58之间的切图权重为:
试用谱聚类算法进行聚类分 析_图切分_59
那么对于我们试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_41个子图点的集合:试用谱聚类算法进行聚类分 析_图切分_55,我们定义切图试用谱聚类算法进行聚类分 析_谱聚类_62为:
试用谱聚类算法进行聚类分 析_谱聚类_63
其中试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_64试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_65的补集

那么如何切图可以让子图内的点权重和高,子图间的点权重和低呢?

一个自然的想法就是最小化试用谱聚类算法进行聚类分 析_谱聚类_66, 但是可以发现,这种极小化的切图存在问题,如下图:

试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_67

为了避免最小切图导致的切图效果不佳,我们需要对每个子图的规模做出限定,一般来说,有两种切图方式,第一种是试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_68,第二种是试用谱聚类算法进行聚类分 析_谱聚类_69

4.1 试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_68切图

对于每个切图,不仅要考虑最小化试用谱聚类算法进行聚类分 析_无向权重图_71,还要考虑最大化每个子图样本的个数,即最小化试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_68函数:
试用谱聚类算法进行聚类分 析_谱聚类_73

我们引入指示向量试用谱聚类算法进行聚类分 析_图切分_74,对于任意一个向量试用谱聚类算法进行聚类分 析_图切分_75,它是一个试用谱聚类算法进行聚类分 析_谱聚类_76维向量(试用谱聚类算法进行聚类分 析_谱聚类_76为样本数),我们定义试用谱聚类算法进行聚类分 析_无向权重图_78为:
试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_79
对于试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_80有:
试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_81

由上式可知,试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_68函数表达式可改写为:
试用谱聚类算法进行聚类分 析_图切分_83
其中试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_84为矩阵的迹,即我们的试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_68切图,实际上是最小化迹试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_84。注意到试用谱聚类算法进行聚类分 析_无向权重图_87,则我们的优化目标为:
试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_88

注意观察试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_84的每一个优化子目标试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_80,其中试用谱聚类算法进行聚类分 析_图切分_91是单位正交基,试用谱聚类算法进行聚类分 析_图切分_92是对称矩阵,此时试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_80是矩阵试用谱聚类算法进行聚类分 析_图切分_92的一个特征值。对于试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_80,我们的目标是找到矩阵试用谱聚类算法进行聚类分 析_图切分_92的最小特征值,而对于试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_97,我们的目标就是找到矩阵试用谱聚类算法进行聚类分 析_图切分_92试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_41个最小特征值。

4.2 试用谱聚类算法进行聚类分 析_谱聚类_69切图

试用谱聚类算法进行聚类分 析_谱聚类_69切图与试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_102切图类似,只是将试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_68的分母试用谱聚类算法进行聚类分 析_谱聚类_104换成试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_105。由于子图样本的个数多不一定权重就大,我们切图时基于权重也更符合我们的目标,因此一般来说试用谱聚类算法进行聚类分 析_谱聚类_69优于试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_68,定义如下:
试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_108

对应的,试用谱聚类算法进行聚类分 析_谱聚类_69切图对指示向量试用谱聚类算法进行聚类分 析_谱聚类_110做了改进,定义如下:
试用谱聚类算法进行聚类分 析_无向权重图_111

我们的优化目标依然是:(推导与试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_68完全一致)
试用谱聚类算法进行聚类分 析_无向权重图_113
但是此时我们的试用谱聚类算法进行聚类分 析_无向权重图_114,而是试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_115。推导如下:
试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_116
也就是说,我们的优化目标最终为:
试用谱聚类算法进行聚类分 析_谱聚类_117
此时我们的试用谱聚类算法进行聚类分 析_图切分_118中的指示向量试用谱聚类算法进行聚类分 析_谱聚类_110不是单位正交基,所以我们令试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_120,则试用谱聚类算法进行聚类分 析_无向权重图_121,也就是优化目标变成了:
试用谱聚类算法进行聚类分 析_图切分_122
可以发现这个式子和试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_68基本一致,只是中间的试用谱聚类算法进行聚类分 析_图切分_92变成了试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_125。这样,我们可以按照试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_68的思想,求出试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_125试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_41个最小特征值

一般来说,试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_125相当于对拉普拉斯矩阵试用谱聚类算法进行聚类分 析_图切分_92做了一次标准化,即试用谱聚类算法进行聚类分 析_图切分_131

5. 谱聚类算法流程

试用谱聚类算法进行聚类分 析_图切分_132

试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_133

  1. 根据邻接矩阵生成方式构建邻接矩阵试用谱聚类算法进行聚类分 析_无向权重图_134,构建度矩阵试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_135
  2. 计算出拉普拉斯矩阵试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_136
  3. 构建标准化后的拉普拉斯矩阵试用谱聚类算法进行聚类分 析_图切分_137
  4. 计算试用谱聚类算法进行聚类分 析_图切分_137最小的试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_139个特征值所各自对应的特征向量试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_29
  5. 将各自对应的特征向量试用谱聚类算法进行聚类分 析_试用谱聚类算法进行聚类分 析_29组成的矩阵按行标准化,最终组成试用谱聚类算法进行聚类分 析_无向权重图_142维矩阵试用谱聚类算法进行聚类分 析_谱聚类_143
  6. 试用谱聚类算法进行聚类分 析_谱聚类_143中的每一行作为一个试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_139维样本,共试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_31个样本,用输入的聚类方法进行聚类,聚类维数为试用谱聚类算法进行聚类分 析_图切分_147
  7. 得到簇划分试用谱聚类算法进行聚类分 析_拉普拉斯矩阵_148

6. 实例演示

import numpy as np 
import matplotlib.pyplot as plt 

from sklearn import cluster, datasets
from sklearn.preprocessing import StandardScaler

np.random.seed(0)

# 构建数据
n_samples = 1500
noisy_circles = datasets.make_circles(n_samples=n_samples, factor=0.5, noise=0.05)
noisy_moons = datasets.make_moons(n_samples=n_samples, noise=0.05)
blobs = datasets.make_blobs(n_samples=n_samples, random_state=8)

data_sets = [
    (
        noisy_circles,
        {
            "n_clusters": 2
        }
    ),
    (
        noisy_moons,
        {
            "n_clusters": 2
        }
    ), 
    (
        blobs, 
        {
            "n_clusters": 3
        }
    )
]
colors = ["#377eb8", "#ff7f00", "#4daf4a"]
affinity_list = ['rbf', 'nearest_neighbors']

plt.figure(figsize=(17, 10))

for i_dataset, (dataset, algo_params) in enumerate(data_sets):
    # 模型参数
    params = algo_params

    # 数据
    X, y = dataset
    X = StandardScaler().fit_transform(X)

    for i_affinity, affinity_strategy in enumerate(affinity_list):
        # 创建SpectralCluster
        spectral = cluster.SpectralClustering(
            n_clusters=params['n_clusters'],
            eigen_solver='arpack', 
            affinity=affinity_strategy
        )

        # 训练
        spectral.fit(X)

        # 预测
        y_pred = spectral.labels_.astype(int)

        y_pred_colors = []

        for i in y_pred:
            y_pred_colors.append(colors[i])
        
        plt.subplot(3, 4, 4*i_dataset+i_affinity+1)
        plt.title(affinity_strategy)
        plt.scatter(X[:, 0], X[:, 1], color=y_pred_colors)

plt.show()

试用谱聚类算法进行聚类分 析_图切分_149

7. 谱聚类算法小结

优点:

  1. 谱聚类只需要数据之间的邻接矩阵,因此对于处理稀疏数据的聚类很有效。这点传统聚类算法比如K-Means很难做到
  2. 由于使用了降维,因此在处理高维数据聚类时的复杂度比传统聚类算法好

缺点:

  1. 如果最终聚类的维度非常高,则由于降维的幅度不够,谱聚类的运行速度和最后的聚类效果均不好
  2. 聚类效果依赖于邻接矩阵,不同的邻接矩阵得到的最终聚类效果可能很不同