SpectralClustering-谱聚类
谱聚类(Spectral Clustering)是一类基于图划分思想的聚类方法。它先根据样本之间的相似性构造图,再对图的拉普拉斯矩阵做特征分解,把样本映射到谱嵌入空间中,最后在嵌入空间内完成标签分配。与 K-Means 主要依赖欧氏空间中的球状簇假设不同,谱聚类更适合发现非凸形…
SpectralClustering-谱聚类
1. 方法概述
谱聚类(Spectral Clustering)是一类基于图划分思想的聚类方法。它先根据样本之间的相似性构造图,再对图的拉普拉斯矩阵做特征分解,把样本映射到谱嵌入空间中,最后在嵌入空间内完成标签分配。与 K-Means 主要依赖欧氏空间中的球状簇假设不同,谱聚类更适合发现非凸形状或流形结构上的簇。
本项目中的 SpectralClustering-谱聚类 模块并不是手写谱图构造和拉普拉斯分解流程,而是对 sklearn.cluster.SpectralClustering 与 sklearn.manifold.spectral_embedding 的工程化封装。根据当前代码,它具有以下特点:
- 支持可选
label_col作为样本名称列; - 支持
rbf与nearest_neighbors两种相似度构造方式; - 支持
kmeans与discretize两种标签分配方式; - 支持
auto、arpack、lobpcg三种特征分解器设置; - 支持
none、minmax、zscore三种预处理方式; - 输出聚类标签、谱嵌入结果、聚类评价指标、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.py、indicators_widget.py、data_validator.py 与 core/calculator.py 的实现,模块对输入数据的真实要求如下:
- 数据不能为空;
- 上传阶段默认要求样本量至少为 3 行;
- 数据中至少存在 1 列可完整转换为数值的列;
- 被选中的特征列必须存在;
- 特征列不能含空值或非数值;
- 特征列不能是常数列;
- 至少选择 1 个特征列;
- 真正开始计算时,还要求样本数满足 \(n>\texttt{n\_clusters}\);
- 当
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\) 对应界面参数 gamma。gamma 越大,相似度对距离变化越敏感。
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 标签分配
当前项目支持两种标签分配方式:
assign_labels="kmeans"assign_labels="discretize"
最终每个样本都会被赋予一个整数簇标签
$$ y_i\in\{0,1,\ldots,K-1\} \tag{11} $$
与 DBSCAN、HDBSCAN 等不同,当前谱聚类模块不会输出噪声标签 -1。
4. 项目中的实现口径
4.1 真正使用的是 sklearn.cluster.SpectralClustering
当前项目把参数直接组装为
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_ 单独调用
spectral_embedding(affinity, n_components=n_clusters, eigen_solver=..., random_state=..., drop_first=True)
从而额外导出 Embedding 工作表。因此:
- 聚类标签来自
SpectralClustering.fit_predict(); - 嵌入结果来自后续的
spectral_embedding(); 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} $$
分别对应:
- 轮廓系数
silhouette_score - Calinski-Harabasz 指数
- Davies-Bouldin 指数
若条件不满足,则这些指标留空字符串。
5.2 Affinity 统计量
项目还会对 affinity 矩阵计算:
Affinity 非零比例Affinity 平均权重Affinity 最小权重Affinity 最大权重
其中非零比例可写为
$$ \rho_A=\frac{\#\{(i,j):A_{ij}\neq 0\}}{n^2} \tag{16} $$
若 affinity 是稀疏矩阵,代码会直接基于非零元素 data 与 nnz 统计;若是稠密矩阵,则只基于非零项做均值、最小值和最大值统计。
5.3 簇汇总表
当前 ClusterSummary 只记录每个簇的:
簇ID样本数样本占比
其中第 \(k\) 个簇的样本占比为
$$ \pi_k=\frac{n_k}{n} \tag{17} $$
6. 代码实现细节
6.1 聚类散点图与嵌入散点图的口径不同
项目会生成两张不同含义的图:
cluster_scatter.pngembedding_scatter.png
其中:
cluster_scatter.png画的是预处理后特征矩阵Xn的前两维;embedding_scatter.png画的是谱嵌入矩阵embedding的前两维;- 两张图都用聚类标签着色。
因此,前者反映的是原特征空间前两维上的簇分布,后者反映的是谱嵌入空间中的分布,二者不能混为一谈。
6.2 random_state 的界面约定
界面中“随机种子(0=不固定)”这一项会在代码里转换为:
0 -> None
因此用户填写 0 并不是把随机种子固定为 0,而是表示不显式固定随机状态。
6.3 ProcessedData 的口径
导出的 ProcessedData 工作表保存的是预处理后的特征矩阵,并在首列附上样本名称列;而 RawData 保存的是上传的原始完整数据表。
7. 算法流程
结合当前项目代码,SpectralClustering-谱聚类 的实际执行流程如下:
- 读取
.xlsx、.xls或.csv文件,并识别可用数值列。 - 在“特征设置”页选择可选的
label_col与参与聚类的特征列。 - 在“算法参数”页设置
n_clusters、affinity、gamma、n_neighbors、assign_labels、n_init、eigen_solver、random_state与normalize。 - 对选中特征执行
none、minmax或zscore预处理。 - 调用
sklearn.cluster.SpectralClustering.fit_predict()完成聚类,并读取affinity_matrix_。 - 基于 affinity 矩阵再次调用
spectral_embedding()生成谱嵌入结果。 - 统计簇大小、样本占比、轮廓系数、CH 指数、DB 指数以及 affinity 统计量。
- 抽样 affinity 子矩阵,生成
Affinity_Sampled。 - 绘制特征空间聚类图和谱嵌入散点图。
- 导出
spectral_results.xlsx,并保存在results/SpectralClustering-谱聚类分析结果_<时间戳>/目录下。
8. 关键参数说明
8.1 n_clusters
目标聚类数,界面范围为 2 到 200,默认值为 3。当前代码要求样本数必须严格大于该值。
8.2 affinity
当前支持:
rbfnearest_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
当前支持:
kmeansdiscretize
前者在谱嵌入空间中做 K-Means,后者采用离散化策略分配标签。
8.6 n_init
重复初始化次数,必须大于 0。该参数主要影响 assign_labels="kmeans" 时的稳定性。
8.7 eigen_solver
当前支持:
autoarpacklobpcg
其中 auto 在代码中会被转为 None,交由 sklearn 自动选择。
8.8 normalize
当前支持:
noneminmaxzscore
由于谱图和相似度矩阵都基于预处理后的数据构造,不同预处理方式会直接影响最终聚类结构。
9. 输出结果与导出说明
9.1 Excel 工作表
根据 _export_excel() 的实现,导出的 Excel 文件包含:
ParametersRawDataProcessedDataLabelsEmbeddingClusterSummaryMetricsAffinity_SampledCharts
其中 Affinity_Sampled 只有在抽样矩阵成功生成时才会出现。
9.2 图表文件
当前图表保存在结果目录下的 plots/ 子目录中,主要包括:
cluster_scatter.pngembedding_scatter.png
导出文件名固定为:
spectral_results.xlsx
10. 论文写作建议
10.1 方法描述模板
“本文采用谱聚类方法对样本进行分组分析。该方法首先根据样本之间的相似性构造邻接图与 affinity 矩阵,然后通过图拉普拉斯的特征分解获得谱嵌入表示,最后在嵌入空间中对样本进行标签分配。本文进一步使用轮廓系数、CH 指数和 DB 指数评估聚类效果。”
10.2 结果解释模板
结果部分可写为:Labels 表反映每个样本的聚类结果,Embedding 表则反映样本在谱嵌入空间中的坐标。Affinity_Sampled 有助于观察相似度矩阵的局部结构,但它只是抽样结果,不代表完整 affinity 矩阵;同时 cluster_scatter.png 与 embedding_scatter.png 表示的空间不同,解释时应加以区分。
10.3 图表题注模板
- 图 1 谱聚类结果散点图(特征空间前两维)。
- 图 2 谱嵌入结果散点图。
- 表 1 谱聚类样本标签结果。
- 表 2 谱聚类评价指标与 affinity 统计结果。
11. 实现说明与注意事项
- 当前模块不会输出噪声点标签,所有样本都会被分配到某个簇。
- 若
label_col被错误勾为特征列,代码会自动把它移出特征集。 Affinity_Sampled只是最多 200 个样本的抽样子矩阵,不是完整 affinity 矩阵。cluster_scatter.png画的是预处理后特征前两维,不是谱嵌入前两维。- 当样本数不大于聚类数,或
nearest_neighbors下邻居数不小于样本数时,程序会直接报错而不是自动修正。
12. 单篇终审补充
12.1 图题与表题对齐建议
当前谱聚类模块的真实工作簿包含:
ParametersRawDataProcessedDataLabelsEmbeddingClusterSummaryMetricsAffinity_Sampled(抽样成功时存在)Charts
这套输出里最容易写混的是 Labels、Embedding 和 Affinity_Sampled。Labels 体现最终聚类结果,Embedding 体现谱嵌入坐标,Affinity_Sampled 只是局部抽样相似度矩阵,三者不应互相替代。
图文件保存在结果目录下的 plots/ 子目录,当前实现真实输出:
cluster_scatter.pngembedding_scatter.png(仅当嵌入维度不少于 2 时生成)
因此图题建议分别写成“谱聚类结果散点图(特征空间前两维)”“谱嵌入结果散点图”。如果当前运行的嵌入维度不足 2,就不应继续保留第二张图的占位描述。
12.2 终审说明
这篇文档最需要强调的工程事实,是 cluster_scatter.png 和 embedding_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,实测工作表为:
ParametersRawDataProcessedDataLabelsEmbeddingClusterSummaryMetricsAffinity_SampledCharts
这里应继续强调 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。 - 正文应围绕
Parameters、RawData、ProcessedData、Similarity、Affinity_Sampled、Embedding、Labels、Charts来写。 - 图证应对应
cluster_scatter.png与embedding_scatter.png,并把原始空间与谱嵌入空间分开说明。 - 复现脚本应按
repro_spectralclustering_谱聚类.py + repro_inputs/spectralclustering_谱聚类_repro_data.csv的口径说明。