基本介绍
谱聚类(Spectral Clustering)是一种基于图论的无监督聚类算法。它通过将数据集表示为图的形式,并利用图的谱特征进行聚类分析。谱聚类算法在图论和线性代数的基础上建立起来,具有较好的聚类性能和理论保证。
图论基础
既然该算法是基于图论的算法,那么要了解谱聚类算法,首先就要学习图的基本概念
图是一种几何结构。图G由顶点(Node)和边(Edge)构成,通常将顶点的集合记为V,边的集合记为E。边由它连接的起点和终点表示。下图是一个典型的图。
上图中的图有7个顶点、7条边。顶点的集合为
边的集合为
图的边可能带有权重,表示两个顶点之间的某种信息,例如两点之间的路线长度。通常情况下,边的权重值表示顶点之间的距离或相似度。对于前者,权重越大说明两个顶点之间距离越远;对于后者,权重越大则说明两个顶点之间的联系越紧密。如不作特殊说明,均认为边的权重是正数。
如果图的边是无向的,则称图为无向图;如果边是有向的,则称图为有向图。
对于顶点的度(Degree)定义为与其有相关边的数量。如上图顶点2的度,因为它与边(1,2),(2,3),(2,4)相关。
对于顶点的加权度定义为与其有相关边的权重和。如上图顶点2的加权度为
邻接矩阵(Adjacent Matrix)是图的矩阵表示,借助它可以方便地存储图的结构,并用线性代数的方法解决图的问题。
如果图有n个顶点,则其邻接矩阵为
的矩阵,矩阵元素
,;表示边
的权重。如果两个顶点之间没有边连接,则在邻接矩阵中对应的元素为
。

加权度矩阵是一个对角矩阵,其主对角线元素为每个顶点的加权度,其他位置的元素为0。即

有了上述理论后我们可以引出拉普拉斯(Laplace)矩阵
拉普拉斯(Laplace)矩阵即为加权度矩阵与邻接矩阵
之差
了解完图的基本概念后,我们边可以学习谱聚类算法
下面是谱聚类算法的详细介绍:
-
构建相似度矩阵(Affinity Matrix): 首先,根据给定的数据集,计算每个样本之间的相似度或距离。常用的相似度度量包括高斯核函数、欧氏距离、余弦相似度等。将相似度或距离构建成一个相似度矩阵,其中每个元素表示对应样本之间的相似度。
-
构建拉普拉斯矩阵(Laplacian Matrix): 将相似度矩阵进行归一化处理,得到归一化的相似度矩阵。然后,通过计算度矩阵(Degree Matrix)和邻接矩阵(Adjacency Matrix)之间的差值,得到拉普拉斯矩阵。拉普拉斯矩阵有多种形式,包括无向图的拉普拉斯矩阵和对称归一化的拉普拉斯矩阵等。
-
特征值分解(Eigenvalue Decomposition): 对拉普拉斯矩阵进行特征值分解,得到其特征值和对应的特征向量。通常情况下,选择前k个最小的非零特征值对应的特征向量作为聚类的输入。
-
聚类操作: 将特征向量构建成一个新的矩阵,然后使用传统的聚类算法(如k-means)对新矩阵进行聚类操作。常用的方法是将特征向量作为数据样本,然后使用k-means算法将其分为k个簇。
-
输出聚类结果: 将聚类操作得到的簇标签作为最终的聚类结果。
在计算边的权值时我们可采用 ϵ邻近法、k近邻法、全连接法。
具体介绍可参考此篇谱聚类算法原理
谱聚类算法代码展示:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
def distance(x, y):
return np.linalg.norm(x-y)
def getDistanceMatrix(data):
# 计算距离矩阵
N, D = data.shape
dists = np.zeros([N, N])
for i in range(N):
for j in range(N):
dists[i, j] = distance(data[i,:], data[j,:])
return dists
def get_WeightMatrix(dists, eps=2, sigma=1):
"""
计算邻接矩阵
计算边的权重: 此处采用的是"全连接法"
使用的是Gaussion核函数: w(ij) = exp[-(xi-xj)^2/2*eps^2]
:param dists: 欧式距离矩阵
:param eps: 高斯核函数的参数
:param sigma: 高斯核函数的参数
:return: 返回一个邻接矩阵
"""
N, D = dists.shape
W = np.zeros([N, N])
for i in range(N):
for j in range(N):
if i != j and dists[i,j] < eps:
W[i, j] = np.exp(-dists[i,j]**2/(sigma**2))
return W
def get_DgreeMatrix(W):
# 计算点的加权度
# 点的 度:与其相关边的数量
# 点的 加权度:与其相关边的权重的和
N, D = W.shape
D = np.zeros([N, N])
for i in range(N):
D[i, i] = np.sum(W[i,:])
return D
def spectral(data, k):
N, D = data.shape
dists = getDistanceMatrix(data)
W = get_WeightMatrix(dists)
D = get_DgreeMatrix(W)
L = D - W # Laplace Matrix 拉普拉斯矩阵
eigvals, eigvecs = np.linalg.eig(L) # 计算特征值和对应的特征向量
# 取特征值最小的k个特征向量
selected_eigvecs = eigvecs[:, np.argsort(eigvals)[:k]]
# 将所取的特征向量组成的矩阵看做一个若干个数据点
# 应用kmeans算法对这些数据点进行聚类,对应的标签就是原数据聚类的标签
kmeans = KMeans(n_clusters=k)
kmeans.fit(selected_eigvecs)
labels = kmeans.labels_
return labels
导入数据
data = np.loadtxt(r"data.txt")
labels = spectral(data, 7)
聚类结果展示
(部分数据,没有调参)
部分参考 雷明——《机器学习的数学》