正在加载中...

展开本页目录
算法教程SpectralClustering-谱聚类

SpectralClustering-谱聚类

No.133 · 在线教程

谱聚类(Spectral Clustering)是一类基于图划分思想的聚类方法。它先根据样本之间的相似性构造图,再对图的拉普拉斯矩阵做特征分解,把样本映射到谱嵌入空间中,最后在嵌入空间内完成标签分配。与 K-Means 主要依赖欧氏空间中的球状簇假设不同,谱聚类更适合发现非凸形…

SpectralClustering-谱聚类

1. 方法概述

谱聚类(Spectral Clustering)是一类基于图划分思想的聚类方法。它先根据样本之间的相似性构造图,再对图的拉普拉斯矩阵做特征分解,把样本映射到谱嵌入空间中,最后在嵌入空间内完成标签分配。与 K-Means 主要依赖欧氏空间中的球状簇假设不同,谱聚类更适合发现非凸形状或流形结构上的簇。

本项目中的 SpectralClustering-谱聚类 模块并不是手写谱图构造和拉普拉斯分解流程,而是对 sklearn.cluster.SpectralClusteringsklearn.manifold.spectral_embedding 的工程化封装。根据当前代码,它具有以下特点:

  1. 支持可选 label_col 作为样本名称列;
  2. 支持 rbfnearest_neighbors 两种相似度构造方式;
  3. 支持 kmeansdiscretize 两种标签分配方式;
  4. 支持 autoarpacklobpcg 三种特征分解器设置;
  5. 支持 noneminmaxzscore 三种预处理方式;
  6. 输出聚类标签、谱嵌入结果、聚类评价指标、Affinity 抽样矩阵与图表。

设共有 \(n\) 个样本、\(p\) 个被选中的特征,记原始特征矩阵为

$$ X=(x_{ij})_{n\times p},\quad i=1,2,\ldots,n,\ j=1,2,\ldots,p \tag{1} $$

若用户指定 label_col,该列只用于样本名称展示,不参与聚类;若未指定,则程序自动生成 样本1, 样本2, \ldots, 样本n 作为样本标识。

2. 数据要求与预处理

2.1 数据约束

根据 upload_widget.pyindicators_widget.pydata_validator.pycore/calculator.py 的实现,模块对输入数据的真实要求如下:

  1. 数据不能为空;
  2. 上传阶段默认要求样本量至少为 3 行;
  3. 数据中至少存在 1 列可完整转换为数值的列;
  4. 被选中的特征列必须存在;
  5. 特征列不能含空值或非数值;
  6. 特征列不能是常数列;
  7. 至少选择 1 个特征列;
  8. 真正开始计算时,还要求样本数满足 \(n>\texttt{n\_clusters}\);
  9. affinity="nearest_neighbors" 时,还要求 n_neighbors < n

另外,若 label_col 被误选入 feature_cols,代码会自动把它从特征列中剔除;如果剔除后特征列为空,则直接报错。

2.2 Min-Max 归一化

normalize="minmax" 时,代码按列执行

$$ z_{ij}=\frac{x_{ij}-x_j^{\min}}{x_j^{\max}-x_j^{\min}} \tag{2} $$

若某列极差为 0,程序会把分母替换为 1。

2.3 Z-score 标准化

normalize="zscore" 时,代码执行

$$ z_{ij}=\frac{x_{ij}-\mu_j}{\sigma_j} \tag{3} $$

其中 \(\sigma_j\) 按 ddof=0 计算;若 \(\sigma_j=0\),同样会用 1 替代。

normalize="none",则直接令

$$ z_{ij}=x_{ij} \tag{4} $$

记进入谱聚类模型的特征矩阵为

$$ Z=(z_{ij})_{n\times p} \tag{5} $$

2.4 符号说明

符号 含义
\(n\) 样本数量
\(p\) 特征维数
\(K\) 聚类数 n_clusters
\(z_i\) 第 \(i\) 个样本的预处理后特征向量
\(A\) 相似度矩阵(affinity matrix)
\(D\) 度矩阵
\(L\) 图拉普拉斯矩阵
\(u_i\) 第 \(i\) 个样本的谱嵌入向量
\(y_i\) 第 \(i\) 个样本的簇标签

3. 核心数学模型

3.1 RBF 相似度

affinity="rbf" 时,谱聚类通常基于高斯核相似度构造图,形式可写为

$$ A_{ij}=\exp\!\big(-\gamma\|z_i-z_j\|_2^2\big) \tag{6} $$

其中 \(\gamma>0\) 对应界面参数 gammagamma 越大,相似度对距离变化越敏感。

3.2 k 近邻相似图

affinity="nearest_neighbors" 时,算法根据近邻关系构造图。可概念性表示为

$$ A_{ij}= \begin{cases} 1, & z_j\in\mathcal{N}_k(z_i)\ \text{或}\ z_i\in\mathcal{N}_k(z_j)\\ 0, & \text{其他} \end{cases} \tag{7} $$

其中 \(\mathcal{N}_k(z_i)\) 表示样本 \(z_i\) 的 \(k\) 近邻集合,\(k=\texttt{n\_neighbors}\)。

3.3 图拉普拉斯与谱嵌入

设度矩阵为

$$ D_{ii}=\sum_{j=1}^{n}A_{ij} \tag{8} $$

则图拉普拉斯可写为

$$ L=D-A \tag{9} $$

谱聚类的核心思想是对拉普拉斯矩阵或其归一化形式做特征分解,并用前若干个特征向量构造嵌入坐标。设样本 \(i\) 的谱嵌入向量为

$$ u_i\in\mathbb{R}^{m} \tag{10} $$

则最终在嵌入空间中对 \(\{u_i\}\) 完成标签分配。

3.4 标签分配

当前项目支持两种标签分配方式:

  1. assign_labels="kmeans"
  2. assign_labels="discretize"

最终每个样本都会被赋予一个整数簇标签

$$ y_i\in\{0,1,\ldots,K-1\} \tag{11} $$

与 DBSCAN、HDBSCAN 等不同,当前谱聚类模块不会输出噪声标签 -1

4. 项目中的实现口径

4.1 真正使用的是 sklearn.cluster.SpectralClustering

当前项目把参数直接组装为

  1. SpectralClustering(n_clusters=..., affinity=..., assign_labels=..., n_init=..., eigen_solver=..., random_state=...)

并在 rbf 情况下额外传入 gamma,在 nearest_neighbors 情况下额外传入 n_neighbors

其中 eigen_solver="auto" 不会原样传入,而是被转换为

$$ \texttt{eigen\_solver}\leftarrow \texttt{None} \tag{12} $$

以使用 sklearn 的默认行为。

4.2 单独计算谱嵌入结果

这是当前模块一个关键实现细节。代码在完成聚类后,又会对模型内部的 affinity_matrix_ 单独调用

  1. spectral_embedding(affinity, n_components=n_clusters, eigen_solver=..., random_state=..., drop_first=True)

从而额外导出 Embedding 工作表。因此:

  1. 聚类标签来自 SpectralClustering.fit_predict()
  2. 嵌入结果来自后续的 spectral_embedding()
  3. Embedding 的列数以 spectral_embedding 实际返回维度为准。

4.3 仅导出 Affinity 抽样矩阵

当前代码不会把完整的 affinity 矩阵整体写入 Excel,而是最多抽取 200 个样本索引,生成一个抽样子矩阵 Affinity_Sampled。当样本数超过 200 时,抽样并不是随机的,而是按索引等间隔选点。

5. 评价指标

5.1 聚类评价指标

若最终聚类数大于 1,且样本数大于聚类数,代码会计算以下指标:

$$ \mathrm{Silhouette}=\frac{1}{n}\sum_{i=1}^{n}\frac{b_i-a_i}{\max(a_i,b_i)} \tag{13} $$

$$ \mathrm{CH}=\frac{\operatorname{tr}(B_K)/(K-1)}{\operatorname{tr}(W_K)/(n-K)} \tag{14} $$

$$ \mathrm{DB}=\frac{1}{K}\sum_{k=1}^{K}\max_{\ell\neq k}\frac{S_k+S_\ell}{M_{k\ell}} \tag{15} $$

分别对应:

  1. 轮廓系数 silhouette_score
  2. Calinski-Harabasz 指数
  3. Davies-Bouldin 指数

若条件不满足,则这些指标留空字符串。

5.2 Affinity 统计量

项目还会对 affinity 矩阵计算:

  1. Affinity 非零比例
  2. Affinity 平均权重
  3. Affinity 最小权重
  4. Affinity 最大权重

其中非零比例可写为

$$ \rho_A=\frac{\#\{(i,j):A_{ij}\neq 0\}}{n^2} \tag{16} $$

若 affinity 是稀疏矩阵,代码会直接基于非零元素 datannz 统计;若是稠密矩阵,则只基于非零项做均值、最小值和最大值统计。

5.3 簇汇总表

当前 ClusterSummary 只记录每个簇的:

  1. 簇ID
  2. 样本数
  3. 样本占比

其中第 \(k\) 个簇的样本占比为

$$ \pi_k=\frac{n_k}{n} \tag{17} $$

6. 代码实现细节

6.1 聚类散点图与嵌入散点图的口径不同

项目会生成两张不同含义的图:

  1. cluster_scatter.png
  2. embedding_scatter.png

其中:

  1. cluster_scatter.png 画的是预处理后特征矩阵 Xn 的前两维;
  2. embedding_scatter.png 画的是谱嵌入矩阵 embedding 的前两维;
  3. 两张图都用聚类标签着色。

因此,前者反映的是原特征空间前两维上的簇分布,后者反映的是谱嵌入空间中的分布,二者不能混为一谈。

6.2 random_state 的界面约定

界面中“随机种子(0=不固定)”这一项会在代码里转换为:

  1. 0 -> None

因此用户填写 0 并不是把随机种子固定为 0,而是表示不显式固定随机状态。

6.3 ProcessedData 的口径

导出的 ProcessedData 工作表保存的是预处理后的特征矩阵,并在首列附上样本名称列;而 RawData 保存的是上传的原始完整数据表。

7. 算法流程

结合当前项目代码,SpectralClustering-谱聚类 的实际执行流程如下:

  1. 读取 .xlsx.xls.csv 文件,并识别可用数值列。
  2. 在“特征设置”页选择可选的 label_col 与参与聚类的特征列。
  3. 在“算法参数”页设置 n_clustersaffinitygamman_neighborsassign_labelsn_initeigen_solverrandom_statenormalize
  4. 对选中特征执行 noneminmaxzscore 预处理。
  5. 调用 sklearn.cluster.SpectralClustering.fit_predict() 完成聚类,并读取 affinity_matrix_
  6. 基于 affinity 矩阵再次调用 spectral_embedding() 生成谱嵌入结果。
  7. 统计簇大小、样本占比、轮廓系数、CH 指数、DB 指数以及 affinity 统计量。
  8. 抽样 affinity 子矩阵,生成 Affinity_Sampled
  9. 绘制特征空间聚类图和谱嵌入散点图。
  10. 导出 spectral_results.xlsx,并保存在 results/SpectralClustering-谱聚类分析结果_<时间戳>/ 目录下。

8. 关键参数说明

8.1 n_clusters

目标聚类数,界面范围为 2200,默认值为 3。当前代码要求样本数必须严格大于该值。

8.2 affinity

当前支持:

  1. rbf
  2. nearest_neighbors

rbf 更适合连续平滑相似度,nearest_neighbors 更适合强调局部连通结构。

8.3 gamma

仅在 affinity="rbf" 时有效,必须大于 0。该值越大,RBF 相似度衰减越快。

8.4 n_neighbors

仅在 affinity="nearest_neighbors" 时有效,要求 2 <= n_neighbors < n。该值决定局部图的连接强度。

8.5 assign_labels

当前支持:

  1. kmeans
  2. discretize

前者在谱嵌入空间中做 K-Means,后者采用离散化策略分配标签。

8.6 n_init

重复初始化次数,必须大于 0。该参数主要影响 assign_labels="kmeans" 时的稳定性。

8.7 eigen_solver

当前支持:

  1. auto
  2. arpack
  3. lobpcg

其中 auto 在代码中会被转为 None,交由 sklearn 自动选择。

8.8 normalize

当前支持:

  1. none
  2. minmax
  3. zscore

由于谱图和相似度矩阵都基于预处理后的数据构造,不同预处理方式会直接影响最终聚类结构。

9. 输出结果与导出说明

9.1 Excel 工作表

根据 _export_excel() 的实现,导出的 Excel 文件包含:

  1. Parameters
  2. RawData
  3. ProcessedData
  4. Labels
  5. Embedding
  6. ClusterSummary
  7. Metrics
  8. Affinity_Sampled
  9. Charts

其中 Affinity_Sampled 只有在抽样矩阵成功生成时才会出现。

9.2 图表文件

当前图表保存在结果目录下的 plots/ 子目录中,主要包括:

  1. cluster_scatter.png
  2. embedding_scatter.png

导出文件名固定为:

  1. spectral_results.xlsx

10. 论文写作建议

10.1 方法描述模板

“本文采用谱聚类方法对样本进行分组分析。该方法首先根据样本之间的相似性构造邻接图与 affinity 矩阵,然后通过图拉普拉斯的特征分解获得谱嵌入表示,最后在嵌入空间中对样本进行标签分配。本文进一步使用轮廓系数、CH 指数和 DB 指数评估聚类效果。”

10.2 结果解释模板

结果部分可写为:Labels 表反映每个样本的聚类结果,Embedding 表则反映样本在谱嵌入空间中的坐标。Affinity_Sampled 有助于观察相似度矩阵的局部结构,但它只是抽样结果,不代表完整 affinity 矩阵;同时 cluster_scatter.pngembedding_scatter.png 表示的空间不同,解释时应加以区分。

10.3 图表题注模板

  • 图 1 谱聚类结果散点图(特征空间前两维)。
  • 图 2 谱嵌入结果散点图。
  • 表 1 谱聚类样本标签结果。
  • 表 2 谱聚类评价指标与 affinity 统计结果。

11. 实现说明与注意事项

  1. 当前模块不会输出噪声点标签,所有样本都会被分配到某个簇。
  2. label_col 被错误勾为特征列,代码会自动把它移出特征集。
  3. Affinity_Sampled 只是最多 200 个样本的抽样子矩阵,不是完整 affinity 矩阵。
  4. cluster_scatter.png 画的是预处理后特征前两维,不是谱嵌入前两维。
  5. 当样本数不大于聚类数,或 nearest_neighbors 下邻居数不小于样本数时,程序会直接报错而不是自动修正。

12. 单篇终审补充

12.1 图题与表题对齐建议

当前谱聚类模块的真实工作簿包含:

  • Parameters
  • RawData
  • ProcessedData
  • Labels
  • Embedding
  • ClusterSummary
  • Metrics
  • Affinity_Sampled(抽样成功时存在)
  • Charts

这套输出里最容易写混的是 LabelsEmbeddingAffinity_SampledLabels 体现最终聚类结果,Embedding 体现谱嵌入坐标,Affinity_Sampled 只是局部抽样相似度矩阵,三者不应互相替代。

图文件保存在结果目录下的 plots/ 子目录,当前实现真实输出:

  • cluster_scatter.png
  • embedding_scatter.png(仅当嵌入维度不少于 2 时生成)

因此图题建议分别写成“谱聚类结果散点图(特征空间前两维)”“谱嵌入结果散点图”。如果当前运行的嵌入维度不足 2,就不应继续保留第二张图的占位描述。

12.2 终审说明

这篇文档最需要强调的工程事实,是 cluster_scatter.pngembedding_scatter.png 对应的是两个不同空间:前者来自预处理后特征前两维,后者来自 spectral_embedding 的嵌入坐标。论文里如果直接拿这两张图做一一位置比较,会产生解释偏差。

另外,当前 repro 脚本已采用 repro_inputs/... 相对路径,结果目录中可见如 repro_inputs/spectralclustering_谱聚类_repro_data.csv 的输入引用。可复现性可按新框架口径写。

12.3 全量强化补充

本篇终审补充绑定的真实算法目录为 具体的算法3/聚类与降维/SpectralClustering-谱聚类,本次采用的代表性结果目录为 具体的算法3/聚类与降维/SpectralClustering-谱聚类/results/SpectralClustering-谱聚类分析结果_20260329_171355。该目录里主工作簿、图文件、复现脚本和 repro_inputs 均来自同一轮结果。

主结果工作簿为 具体的算法3/聚类与降维/SpectralClustering-谱聚类/results/SpectralClustering-谱聚类分析结果_20260329_171355/spectral_results.xlsx,实测工作表为:

  • Parameters
  • RawData
  • ProcessedData
  • Labels
  • Embedding
  • ClusterSummary
  • Metrics
  • Affinity_Sampled
  • Charts

这里应继续强调 Affinity_Sampled 是抽样相似度矩阵,不是完整 affinity 矩阵;Embedding 是谱嵌入坐标;Labels 是最终聚类标签。三者在论文结果解释中不能互相替代。

本轮真实图文件为:

  • 具体的算法3/聚类与降维/SpectralClustering-谱聚类/results/SpectralClustering-谱聚类分析结果_20260329_171355/plots/cluster_scatter.png
  • 具体的算法3/聚类与降维/SpectralClustering-谱聚类/results/SpectralClustering-谱聚类分析结果_20260329_171355/plots/embedding_scatter.png

这两张图分别对应特征空间前两维与谱嵌入空间,因此图题和正文解释必须分开写,不能把 cluster_scatter.png 当成谱嵌入图,也不能把 embedding_scatter.png 当成原始特征散点图。

复现实物方面,该目录实际包含:

  • 具体的算法3/聚类与降维/SpectralClustering-谱聚类/results/SpectralClustering-谱聚类分析结果_20260329_171355/repro_spectralclustering_谱聚类.py
  • 具体的算法3/聚类与降维/SpectralClustering-谱聚类/results/SpectralClustering-谱聚类分析结果_20260329_171355/repro_inputs/spectralclustering_谱聚类_repro_data.csv
  • 具体的算法3/聚类与降维/SpectralClustering-谱聚类/results/SpectralClustering-谱聚类分析结果_20260329_171355/repro_inputs/window2_spectral_baseline_input.csv

脚本中实际绑定的是 INPUT_FILE = 'repro_inputs/spectralclustering_谱聚类_repro_data.csv'。因此同目录下的 window2_spectral_baseline_input.csv 应视为额外保留的输入副本,不能写成当前脚本实际使用的输入文件。

11. 软件实现核查补充(2026-07)

  • 当前主结果目录应写作 具体的算法3/聚类与降维/SpectralClustering-谱聚类/results/SpectralClustering-谱聚类分析结果_20260329_171355
  • 正文应围绕 ParametersRawDataProcessedDataSimilarityAffinity_SampledEmbeddingLabelsCharts 来写。
  • 图证应对应 cluster_scatter.pngembedding_scatter.png,并把原始空间与谱嵌入空间分开说明。
  • 复现脚本应按 repro_spectralclustering_谱聚类.py + repro_inputs/spectralclustering_谱聚类_repro_data.csv 的口径说明。