SPE-随机邻近嵌入
随机邻近嵌入(Stochastic Proximity Embedding, SPE)是一类距离保持型降维方法。它的基本思想不是一次性求解完整矩阵分解,而是在迭代过程中反复随机抽取样本点对,根据低维距离与高维目标距离之间的偏差,对嵌入坐标做局部修正,逐步逼近原空间的距离结构。
SPE-随机邻近嵌入
1. 方法概述
随机邻近嵌入(Stochastic Proximity Embedding, SPE)是一类距离保持型降维方法。它的基本思想不是一次性求解完整矩阵分解,而是在迭代过程中反复随机抽取样本点对,根据低维距离与高维目标距离之间的偏差,对嵌入坐标做局部修正,逐步逼近原空间的距离结构。
本项目中的 SPE-随机邻近嵌入 模块并不是调用现成的 sklearn SPE 接口,而是自行实现了随机点对更新流程。根据当前代码,它具有以下特点:
- 固定要求第 1 列为样本 ID,后续列为数值特征;
- 支持
none、standard、minmax三种特征预处理方式; - 支持
random与pca两种初始化; - 每轮随机抽取一批点对进行更新;
- 学习率按迭代次数线性衰减,并设置最小下限;
- 输出低维嵌入结果、
stress_mse、stress_mae与二维散点图。
设共有 \(n\) 个样本、\(p\) 个被选中的特征,记原始特征矩阵为
$$ X=(x_{ij})_{n\times p},\quad i=1,2,\ldots,n,\ j=1,2,\ldots,p \tag{1} $$
程序默认第 1 列是样本名称列,不参与距离计算。
2. 数据要求与预处理
2.1 数据约束
根据 upload_widget.py、indicators_widget.py、data_validator.py 与 core/spe_calculator.py 的实现,模块对输入数据的真实要求如下:
- 数据不能为空;
- 至少包含两列,即第 1 列对象名称和至少 1 列特征;
- 第 1 列对象名称不能重复;
- 第 2 列及以后必须是数值型列;
- 特征列不能含空值;
- 特征列不能是常数列;
- 至少选择 1 个特征列;
- 真正开始计算时,样本量还必须满足 \(n\ge 2\)。
当前模块没有单独的 label_col 选择逻辑,首列就是固定的样本标识列。
2.2 Z-score 标准化
当 normalization="standard" 时,代码调用 StandardScaler() 执行
$$ z_{ij}=\frac{x_{ij}-\mu_j}{\sigma_j} \tag{2} $$
2.3 Min-Max 归一化
当 normalization="minmax" 时,代码调用 MinMaxScaler() 执行
$$ z_{ij}=\frac{x_{ij}-x_j^{\min}}{x_j^{\max}-x_j^{\min}} \tag{3} $$
若 normalization="none",则直接令
$$ z_{ij}=x_{ij} \tag{4} $$
记用于构造目标距离矩阵的预处理后特征矩阵为
$$ Z=(z_{ij})_{n\times p} \tag{5} $$
2.4 符号说明
| 符号 | 含义 |
|---|---|
| \(n\) | 样本数量 |
| \(p\) | 特征维数 |
| \(q\) | 目标嵌入维数 n_components |
| \(z_i\) | 第 \(i\) 个样本的预处理后特征向量 |
| \(y_i\) | 第 \(i\) 个样本的低维嵌入坐标 |
| \(\delta_{ij}\) | 原空间目标距离 |
| \(d_{ij}\) | 当前低维距离 |
| \(T\) | 最大迭代次数 |
| \(s\) | 每轮采样点对数 sample_size |
| \(\eta_t\) | 第 \(t\) 次迭代学习率 |
3. 核心数学模型
3.1 目标距离矩阵
代码先基于预处理后的矩阵 \(Z\) 计算欧氏距离矩阵:
$$ \delta_{ij}=\|z_i-z_j\|_2 \tag{6} $$
这一步通过 pairwise_distances(X, metric="euclidean") 完成,因此后续 SPE 更新想要逼近的是真正经过预处理后的高维距离关系。
3.2 低维嵌入表示
设低维嵌入维数为 \(q\),则每个样本对应一个坐标向量
$$ y_i\in\mathbb{R}^{q},\quad i=1,2,\ldots,n \tag{7} $$
对任意一对样本 \((i,j)\),当前低维距离为
$$ d_{ij}=\|y_i-y_j\|_2 \tag{8} $$
3.3 线性衰减学习率
在第 \(t\) 次迭代时,代码把初始学习率 learning_rate 按线性方式衰减为
$$ \eta_t=\eta_0\left(1-\frac{t}{T}\right) \tag{9} $$
若该值不再为正,则代码会强制设为
$$ \eta_t\leftarrow 10^{-6} \tag{10} $$
3.4 随机点对更新
每轮迭代中,程序随机生成一批样本索引对 \((i,j)\),并剔除掉 \(i=j\) 的情况。对保留下来的点对,先计算误差
$$ e_{ij}=d_{ij}-\delta_{ij} \tag{11} $$
再构造更新系数
$$ \alpha_{ij}=\eta_t\frac{e_{ij}}{d_{ij}} \tag{12} $$
并按如下方式同步修正两个端点的低维坐标:
$$ y_i\leftarrow y_i-\alpha_{ij}(y_i-y_j),\qquad y_j\leftarrow y_j+\alpha_{ij}(y_i-y_j) \tag{13} $$
这就是当前实现中的 SPE 核心更新机制。
需要注意,代码注释写的是“无重复组合”,但实际实现只是分别随机生成 idx_i 与 idx_j 并过滤 i==j,并没有真正去重,因此同一轮内点对仍可能重复出现。
4. 初始化与参数口径
4.1 random 初始化
当 init="random" 时,代码用
rng.normal(scale=0.01, size=(n_samples, n_components))
生成初始低维坐标,因此初始嵌入是一个小方差随机正态云。
4.2 pca 初始化
当 init="pca" 且
$$ q\le p \tag{14} $$
时,程序会尝试调用 PCA(n_components=q).fit_transform(X) 作为初始坐标。
但需要特别注意两个代码细节:
- 若
PCA计算失败,会自动回退到随机正态初始化; - 若 \(q>p\),代码也不会报错,而是直接跳过 PCA 初始化,退回到随机初始化。
4.3 sample_size 的实际使用
代码会把每轮采样点对数裁剪为
$$ s=\min\!\left(\texttt{sample\_size},\ \frac{n(n-1)}{2}\right) \tag{15} $$
但由于后续是随机生成索引并过滤 \(i=j\),所以最终真正参与更新的点对数量可能少于这个值。
5. 评价指标
5.1 stress_mse
拟合完成后,代码会重新计算低维距离矩阵 \(D=(d_{ij})\),并与目标距离矩阵 \(\Delta=(\delta_{ij})\) 比较。均方误差定义为
$$ \mathrm{stress\_mse}=\frac{1}{n^2}\sum_{i=1}^{n}\sum_{j=1}^{n}(d_{ij}-\delta_{ij})^2 \tag{16} $$
5.2 stress_mae
平均绝对误差定义为
$$ \mathrm{stress\_mae}=\frac{1}{n^2}\sum_{i=1}^{n}\sum_{j=1}^{n}|d_{ij}-\delta_{ij}| \tag{17} $$
这里的计算直接基于完整距离矩阵,因此对角线上的 0 也包含在平均中。
5.3 统计表字段
当前 Stats 工作表中固定包含:
stress_msestress_maemax_itersample_sizelearning_raten_components
6. 代码实现细节
6.1 结果表的口径
导出的 Embedded 工作表会保留首列样本 ID,并输出
Dim1Dim2- ...
Dimq
其中 \(q=\texttt{n\_components}\)。
6.2 图表生成条件
当前散点图不是任何情况下都会生成。代码要求
embedded.shape[1] >= 3
才会保存 scatter.png。由于 embedded 的第一列是样本 ID,这实际上等价于:
- 嵌入维度至少为 2;
- 只有
Dim1与Dim2会被画出来。
若 n_components=1,则不会生成散点图。
6.3 Features 工作表不是预处理后的数据
这是当前模块一个很容易写错的地方。导出的 Features 工作表保存的是
self.features
也就是用户选中的原始特征值,而不是标准化或 Min-Max 变换后的矩阵。真正参与目标距离计算的预处理矩阵只存在于内存中,没有单独导出为 Excel 工作表。
7. 算法流程
结合当前项目代码,SPE-随机邻近嵌入 的实际执行流程如下:
- 读取
.xlsx、.xls或.csv文件,并校验首列样本 ID 与后续特征列。 - 在“特征选择”页勾选参与嵌入的特征列。
- 在“方法与参数”页设置
n_components、max_iter、sample_size、learning_rate、init、normalization与random_state。 - 对选中特征按
none、standard或minmax进行预处理。 - 计算预处理后高维样本之间的欧氏距离矩阵,作为 SPE 的目标距离。
- 按
random或pca方式初始化低维坐标。 - 在每一轮中随机抽取样本点对,按当前距离误差更新两端点坐标,并使学习率线性衰减。
- 迭代结束后计算
stress_mse与stress_mae。 - 当嵌入维度不少于 2 时,生成
scatter.png。 - 导出
spe_results_<时间戳>.xlsx,并在同级目录下生成spe_plots_<时间戳>/图表目录。
8. 关键参数说明
8.1 n_components
目标嵌入维度,界面范围为 1 到 50,默认值为 2。当取 2 时最方便直接查看散点图结果。
8.2 max_iter
最大迭代次数,默认值为 300。该值越大,通常越有机会让低维距离逐步逼近目标距离,但计算时间也会增加。
8.3 sample_size
每轮更新时抽取的样本点对数量。该值越大,单轮更新覆盖的距离关系越多,但每轮计算量也更大。
8.4 learning_rate
初始学习率,必须大于 0。代码会按线性规则逐步衰减,并设置下限 1e-6。
8.5 init
当前支持:
randompca
其中 pca 更适合把初始位置放在一个相对稳定的低维结构上,但并不保证一定成功,失败时会自动回退到随机初始化。
8.6 normalization
当前支持:
nonestandardminmax
由于目标距离矩阵直接基于预处理后的特征计算,不同预处理方式会显著改变嵌入结果。
9. 输出结果与导出说明
9.1 Excel 工作表
根据 save_to_excel() 的实现,导出的 Excel 文件包含:
RawDataFeaturesEmbeddedStatsParametersCharts
其中:
RawData保存原始完整数据;Features保存选中的原始特征列;Embedded保存低维嵌入结果;Charts记录图表路径,同时保留中英文字段列名。
9.2 结果文件与图表目录
当前结果目录固定形如:
results/SPE-随机邻近嵌入分析结果_<时间戳>/
其中导出文件命名为:
spe_results_<时间戳>.xlsx
若生成散点图,则图表目录命名为:
spe_plots_<时间戳>/scatter.png
10. 论文写作建议
10.1 方法描述模板
“本文采用随机邻近嵌入(SPE)方法对高维样本进行降维表示。该方法首先计算样本在预处理特征空间中的目标距离矩阵,然后在低维空间中随机抽取样本点对,根据当前低维距离与目标距离的偏差反复修正样本坐标,从而逐步保持原始距离结构。本文使用 stress 均方误差和平均绝对误差评价嵌入质量。”
10.2 结果解释模板
结果部分可写为:Embedded 表中的 Dim1、Dim2 等是最终低维坐标。若 stress_mse 和 stress_mae 越小,通常说明低维空间更好地保持了原空间距离关系;若使用了 standard 或 minmax,则应在论文中明确说明目标距离是基于预处理后的特征计算的。
10.3 图表题注模板
- 图 1 SPE 二维嵌入散点图。
- 表 1 SPE 低维嵌入坐标结果。
- 表 2 SPE 嵌入误差指标与参数设置。
11. 实现说明与注意事项
- 当前模块只支持“首列样本名,后续列为数值特征”的数据结构。
pca初始化并不总是成功,失败后会自动回退到随机初始化。sample_size经过裁剪后仍不代表每轮一定有那么多个不重复点对参与更新。Features工作表保存的是原始选中特征,而不是预处理后的特征矩阵。- 当
n_components=1时不会生成二维散点图,但嵌入结果仍会正常导出。
12. 单篇终审补充
12.1 图题与表题对齐建议
当前 SPE 模块的真实工作簿包含:
RawDataFeaturesEmbeddedStatsParametersCharts
其中 Embedded 是论文中最适合作为核心结果表引用的页;Stats 负责承接 stress_mse、stress_mae 等嵌入误差指标。不要把 Features 误写成“预处理特征矩阵”,因为当前程序并未把预处理后的矩阵单独导出到 Excel。
图文件保存在结果目录下的 spe_plots_<suffix>/ 子目录,当前真实图名为:
scatter.png
而 Charts 表中的图表名写的是 embedding_scatter。因此论文图题建议写成“SPE 二维嵌入散点图”;正文中可以说明图表索引名为 embedding_scatter,但不需要把文件名 scatter.png 原样写进标题。
12.2 终审说明
这篇文档最需要避免的误写,是把 SPE 的目标距离理解为来自 Features 工作表。当前实现先对特征做可能的标准化/归一化,再基于预处理后的矩阵构造 target_dist,但 Excel 里导出的 Features 仍是原始选中特征。因此“导出表”和“内部优化距离空间”并不是同一口径。
另外,当前 repro 脚本已经使用 repro_inputs/... 相对路径,结果目录中可见如 repro_inputs/spe_随机邻近嵌入_repro_data.csv 的输入引用。这篇在可复现性表述上可以按新框架写。
12.3 全量强化补充
本篇终审补充绑定的真实算法目录为 具体的算法3/聚类与降维/SPE-随机邻近嵌入,本次采用的代表性结果目录为 具体的算法3/聚类与降维/SPE-随机邻近嵌入/results/SPE-随机邻近嵌入分析结果_20260322_043459_enhanced。
当前目录中真实存在两份工作簿:
spe_export.xlsxspe_repro.xlsx
两者实测工作表一致,均为:
RawDataFeaturesEmbeddedStatsParametersCharts
因此这一轮应把 spe_export.xlsx 视为主结果,把 spe_repro.xlsx 视为 repro 再生产物。两者结构相同,但不能在文档中写成“单个结果文件”。
当前目录中的真实图文件也分成两套:
具体的算法3/聚类与降维/SPE-随机邻近嵌入/results/SPE-随机邻近嵌入分析结果_20260322_043459_enhanced/spe_plots_20260322_043459/scatter.png具体的算法3/聚类与降维/SPE-随机邻近嵌入/results/SPE-随机邻近嵌入分析结果_20260322_043459_enhanced/spe_plots_20260322_043500/scatter.png
这说明当前磁盘同时保留了主结果散点图与 repro 重跑散点图。它们图义一致,都是嵌入散点图;区别在于来源批次,而不是图类型差异。
复现实物方面,该目录实际包含:
具体的算法3/聚类与降维/SPE-随机邻近嵌入/results/SPE-随机邻近嵌入分析结果_20260322_043459_enhanced/repro_spe_随机邻近嵌入.py具体的算法3/聚类与降维/SPE-随机邻近嵌入/results/SPE-随机邻近嵌入分析结果_20260322_043459_enhanced/repro_inputs/spe_随机邻近嵌入_repro_data.csv
脚本中明确写成 INPUT_FILE = 'repro_inputs/spe_随机邻近嵌入_repro_data.csv'、OUTPUT_DIR = '.'、OUTPUT_FILE = 'spe_repro.xlsx'。因此这一轮的真实可复现口径是“结果目录内部输入副本 + 同目录 repro 结果工作簿与图目录”,而不是重新依赖外部 uploads/ 文件。
11. 软件实现核查补充(2026-07)
- 当前主结果目录应写作
具体的算法3/聚类与降维/SPE-随机邻近嵌入/results/SPE-随机邻近嵌入分析结果_20260322_043459_enhanced。 - 正文应围绕
RawData、ProcessedData、Embedding、Stats、Parameters、Charts来写。 - 图证应对应两轮
scatter.png,并把主结果与 repro 再生产物区分开。 - 复现脚本应按
repro_spe_随机邻近嵌入.py + repro_inputs/spe_随机邻近嵌入_repro_data.csv的口径说明。