[机器学习复习笔记] Spectral Clustering 谱聚类

发布时间 2023-11-05 23:52:44作者: Amαdeus

Spectral Clustering 谱聚类

1. 邻接矩阵

无向图 \(G = (V, E)\),所有顶点之间的权重构成一个 \(n \times n\) 的矩阵:

\[W = \begin{bmatrix} w_{11} & w_{12} & \cdots & w_{1n} \\ w_{21} & w_{22} & \cdots & w_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ w_{n1} & w_{n2} & \cdots & w_{nn} \end{bmatrix} \]

邻接矩阵 \(W\)\(w_{ij} = w_{ji}\)


2. 度与度矩阵

传统的节点的度数指的是相连的边的个数,但在谱聚类问题中,有些不一样,公式如下:

\[d_i = \sum_{n}^{j = 1} w_{ij} \]

即节点 \(i\) 的度数为所有邻接的边的权值之和

由此可以得到度矩阵

\[D = \begin{bmatrix} d_1 & 0 & \cdots & 0 \\ 0 & d_2 & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \cdots & 0 \end{bmatrix} \]


3. 相似矩阵及衡量方法

图中各个顶点的相似度衡量主要基于距离的度量,也就是说空间两个点的距离越近,则它们越相似,距离越远,则它们越不相似。通过 样本点 之间的距离 \(s_{ij}\) 得到 相似图矩阵 \(S\) ,以此来得到 邻接矩阵 \(W\)

在向量空间中任意两个向量 \(x_i\)
\(x_j\)
的距离为 \(s_{ij} = ||x_i - x_j||^2_2\)
​​​。

以下是三种相似图衡量方法(相似矩阵的计算方法)。

  • \(\epsilon\) — 近邻法

    采用欧式距离计算两个顶点的距离,设定一个阈值 \(\epsilon\),使得:

    \[w_{ij} = \begin{cases} 0, & s_{ij} > \epsilon \\ \epsilon, & s_{ij} \le \epsilon \end{cases} \]

  • \(k\) 近邻法

    取与顶点最近的 \(k\) ​个顶点,该顶点与这 \(k\) 个顶点的权重都大于0,但这会导致最后所得的相似矩阵不一定是对称的,因为一个点 \(v_i\) 在另外一个点 \(v_j\)\(k\) 个近邻中,并不能保证 \(v_i\) 也在点 \(v_j\)\(k\) 个近邻中。

    有两种方法可以解决不对称的问题:

    • 两个顶点 \(v_i\)\(v_j\) 存在其中一个点在另一个点的 \(k\) 近邻中,则令 \(w_{ij} = w_{ji} = \frac{1}{s_{ij}}\);反之,则令 \(w_{ij} = w_{ji} = 0\)

    \[w_{ij} = w_{ji} = \begin{cases} 0, & v_i \not \in \text{KNN}(v_j) \; \text{and} \; v_j \not \in \text{KNN}(v_i) \\ \frac{1}{s_{ij}}, & v_i \in \text{KNN}(v_j) \; \text{or} \; v_j \in \text{KNN}(v_i) \end{cases} \]

    • 两个顶点 \(v_i\)\(v_j\) 只有同时在对方的 \(k\) 近邻中,则令 \(w_{ij} = w_{ji} = \frac{1}{s_{ij}}\);反之,则令 \(w_{ij} = w_{ji} = 0\)

    \[w_{ij} = w_{ji} = \begin{cases} 0, & v_i \not \in \text{KNN}(v_j) \; \text{or} \; v_j \not \in \text{KNN}(v_i) \\ \frac{1}{s_{ij}}, & v_i \in \text{KNN}(v_j) \; \text{and} \; v_j \in \text{KNN}(v_i) \end{cases} \]

  • 全连接法

    将所有的顶点都连接起来。然后通过度量空间中某种对称度量算子来计算顶点之间的相似度。

    此处以 高斯核 \(\text{RBF}\) 函数为例(也可以是多项式核函数、 \(\text{sigmoid}\) 函数),计算两个顶点之间的相似度:

    \[w_{ij} = w_{ji} = \text{exp}(- \frac{||v_i - v_j||^2_2}{2 \sigma^2}) \]

    高斯核函数的曲线其实也是一个高斯分布图。高斯核里有运用到euclidean distance(欧几里得距离),顶点距离也是越远相似度越低,这和高斯核是符合的。另外高斯核的度量都是大于0,这也符合谱聚类中对于相似度量的要求。

    还有一点就是,使用的二范数的平方这一度量来衡量相似度,所以这也满足了所求相似矩阵是一个对称矩阵的要求。


4. 拉普拉斯矩阵

4.1 非规范化的图拉普拉斯矩阵

也叫图拉普拉斯矩阵,此处的 \(L\)非规范化的图拉普拉斯矩阵

\[L = D - W \]

其中 \(D\) 为度矩阵,\(W\) 为邻接矩阵。

4.2 规范化的图拉普拉斯矩阵

有如下两种规范化图拉普拉斯矩阵:

\[L_{\text{sym}} = D^{- \frac{1}{2}}LD^{- \frac{1}{2}} = I - D^{- \frac{1}{2}}WD^{-\frac{1}{2}} \]

\[L_{\text{rw}} = D^{-1}L = I - D^{-1}W \]

其中 \(L_{\text{sym}}\)对称矩阵\(\text{sym}\) 为单词symmetric缩写; \(L_{\text{rw}}\) 与随机游走相关,超过了课程考试讨论的范围,不多说了。 主要是我也不会


5. 谱聚类的过程

任务是要分成 \(k\) 类,得到簇划分 \(\mathcal C = \{C_1, C_2, \cdots , C_k \}\)

  1. 计算样本点之间的距离,得到 相似矩阵 $S ;

  2. 选择一个衡量方法(一般选择全连接法,即使用 \(\text{RBF}\) 高斯核函数 计算相似度),通过 相似矩阵 \(S\) 得到 邻接矩阵 \(W\)

  3. 根据 邻接矩阵 \(W\) 来计算得到 度矩阵 \(D\)

  4. 通过 \(L = D - W\) 计算得到 拉普拉斯矩阵 \(L\)

  5. 拉普拉斯矩阵 \(L\) 进行标准化,即构建 规范化拉普拉斯矩阵\(D^{- \frac{1}{2}}LD^{- \frac{1}{2}}\) (一般采用第一种,当然不进行规范化也是可以的);

  6. 拉普拉斯矩阵 进行 特征值分解,获取前 \(k\) 小的特征值对应的特征向量,构成特征矩阵 \(Q\),有 \(Q = [q_1, q_2, \cdots, q_k]\),其中 \(q_i\) 是大小为 \(1 \times n\) 的列向量,表示选取的第 \(i\) 小的特征向量;

  7. 特征矩阵 \(Q\) 中的所有行 \(r_1, r_2, \cdots, r_n\) 进行 聚类,一般使用 \(\text{K-means}\) 算法进行聚类,得到簇划分 \(\mathcal C = \{C_1, C_2, \cdots , C_k \}\)

  8. 得到原始数据分组 \(\mathcal A = \{A_1, A_2, \cdots , A_k \}\) ,其中 \(A_i = \{v_j | r_j \in C_i\}\)\(v_j\) 为第 \(j\) 个样本点,\(r_j\) 为第 \(j\) 个样本点对应的所构成的 特征矩阵 \(Q\) 的行特征向量)。

PS:第 5 步可以省去,直接对 拉普拉斯矩阵 \(L\) 进行特征值分解。


6. 谱聚类核心代码

6.1 手写实现

import numpy as np
from sklearn.metrics import pairwise_distances
from sklearn.cluster import KMeans
from sklearn.cluster import SpectralClustering

X, y = ... # 数据

# 相似度矩阵,使用 RBF
def w(x, y, sigma=2.50):
    return np.exp(-1.0 * (x - y).T @ (x - y) /(2 * sigma**2)) # 高斯径向基核函数

# 邻接矩阵
W = pairwise_distances(X, metric=w)

# 度矩阵
D = np.diag(W.sum(axis=1))

# 拉普拉斯矩阵
L = D - W

# 拉普拉斯矩阵规范化,不计算也行
L_norm = np.sqrt(np.linalg.inv(D)) @ L @ np.sqrt(np.linalg.inv(D))

# 特征分解
eigenvals, eigvector = np.linalg.eig(L_norm)

# 将特征值按照升序排列
ind = np.argsort(eigenvals)
eig_vec_sorted = eigvector[:,ind] #对应的特征向量也要相应调整顺序

# 取出前k个最小的特征值对应的特征向量,k和要聚类的簇数一样
k = 3
Q = eig_vec_sorted[:, :k] # 特征矩阵

# 对特征矩阵Q进行聚类 训练得到模型
model = KMeans(n_clusters=k)
Q = np.real(Q)

# 用得到的模型进行预测
y_pred = model.fit_predict(Q)

6.2 调用 sklearn 实现

from sklearn.cluster import SpectralClustering 

X, y = ... # 数据

# 谱聚类
k = 3
model = SpectralClustering(n_clusters=k) 

# 预测
y_pred = model.fit_predict(X) 

参考文章

一文带你深入浅出地搞懂谱聚类

谱聚类算法