正在加载中...

展开本页目录
算法教程SOM-自组织映射

SOM-自组织映射

No.131 · 在线教程

自组织映射(Self-Organizing Map, SOM)是一类无监督神经网络方法,其目标是在尽量保持样本拓扑关系的同时,把高维特征映射到一个低维离散网格上。与 PCA、MDS、t-SNE 这类直接输出连续低维坐标的方法不同,SOM 的输出更像是一个二维神经元网格,每个样本…

SOM-自组织映射

1. 方法概述

自组织映射(Self-Organizing Map, SOM)是一类无监督神经网络方法,其目标是在尽量保持样本拓扑关系的同时,把高维特征映射到一个低维离散网格上。与 PCA、MDS、t-SNE 这类直接输出连续低维坐标的方法不同,SOM 的输出更像是一个二维神经元网格,每个样本会被映射到某个最佳匹配单元(BMU, Best Matching Unit)上。

本项目中的 SOM-自组织映射 模块并不是调用第三方 SOM 库,而是对 SOM 训练流程进行了直接实现。根据当前代码,它具有以下特点:

  1. 固定要求第 1 列为样本 ID,后续列为数值特征;
  2. 支持在第 2 列及以后勾选参与训练的特征列;
  3. 支持 standardize=True/False,即是否执行 z-score 标准化;
  4. 支持 randomsample 两种权重初始化方式;
  5. 使用二维矩形网格、欧氏距离 BMU 搜索和高斯邻域更新;
  6. 输出 BMU 映射表、权重向量表、U-Matrix、量化误差与拓扑误差。

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

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

其中程序默认第 1 列是样本名称列,不会参与 SOM 训练。

2. 数据要求与预处理

2.1 数据约束

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

  1. 数据不能为空;
  2. 至少包含两列,即第 1 列对象名称和至少 1 列特征;
  3. 第 1 列对象名称不能重复;
  4. 第 2 列及以后必须是数值型列;
  5. 特征列不能含空值;
  6. 至少选择 1 个特征列;
  7. 网格尺寸 map_rowsmap_cols 都必须不小于 2;
  8. iterations 必须不小于 10;
  9. learning_ratesigma 必须为正数。

与前面一些聚类模块不同,这个 SOM 实现没有额外检查常数列,也没有可选的 label_col 逻辑。

2.2 标准化方式

standardize=True 时,代码会对每个特征执行 z-score 标准化:

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

其中 \(\mu_j\) 为第 \(j\) 个特征均值,\(\sigma_j\) 为按 ddof=0 计算的总体标准差。若某列满足 \(\sigma_j=0\),代码会把该列标准差替换为 1。

standardize=False,则直接令

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

记进入 SOM 训练的特征矩阵为

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

2.3 符号说明

符号 含义
\(n\) 样本数量
\(p\) 特征维数
\(R,C\) SOM 网格的行数与列数
\(M=RC\) 神经元总数
\(z_i\) 第 \(i\) 个样本的预处理后特征向量
\(w_m\) 第 \(m\) 个神经元的权重向量
\(b(i)\) 样本 \(z_i\) 的 BMU 索引
\(\eta_t\) 第 \(t\) 次迭代的学习率
\(\sigma_t\) 第 \(t\) 次迭代的邻域半径
\(U\) U-Matrix

3. 核心数学模型

3.1 二维网格与权重向量

代码先建立一个 \(R\times C\) 的二维矩形网格,共有

$$ M=R\times C \tag{5} $$

个神经元。每个神经元 \(m\) 对应一个权重向量

$$ w_m\in\mathbb{R}^{p},\quad m=1,2,\ldots,M \tag{6} $$

3.2 BMU 搜索

对任意样本 \(z_i\),程序使用欧氏距离寻找最佳匹配单元:

$$ b(i)=\arg\min_{1\le m\le M}\|z_i-w_m\|_2 \tag{7} $$

代码中的 _bmu() 正是按这个规则在全部节点上逐一比较并取最小距离索引。

3.3 指数衰减学习率与邻域半径

在第 \(t\) 次迭代时,代码把初始学习率 learning_rate 和初始邻域半径 sigma 按指数形式衰减:

$$ \eta_t=\eta_0\exp\!\left(-\frac{t}{T}\right) \tag{8} $$

$$ \sigma_t=\sigma_0\exp\!\left(-\frac{t}{T}\right) \tag{9} $$

其中 \(T=\texttt{iterations}\)。

3.4 高斯邻域函数与权重更新

设第 \(m\) 个节点在网格中的坐标为 \(r_m\),BMU 节点坐标为 \(r_{b(i)}\)。代码先计算网格距离平方

$$ d_m^2=\|r_m-r_{b(i)}\|_2^2 \tag{10} $$

再构造高斯邻域函数

$$ h_{m,t}=\exp\!\left(-\frac{d_m^2}{2\sigma_t^2}\right) \tag{11} $$

并执行权重更新:

$$ w_m^{(t+1)}=w_m^{(t)}+\eta_t h_{m,t}\big(z_i-w_m^{(t)}\big) \tag{12} $$

这正是 _train() 中的核心更新逻辑。

3.5 U-Matrix

当前项目的 U-Matrix 并不是任意邻接定义,而是仅考虑每个节点上下左右四个方向的直接邻居。对网格位置 \((r,c)\),其 U 值为该节点与所有有效四邻域节点权重距离的平均值:

$$ U_{rc}=\frac{1}{|\mathcal{N}_{rc}|}\sum_{m'\in\mathcal{N}_{rc}}\|w_{rc}-w_{m'}\|_2 \tag{13} $$

其中 \(\mathcal{N}_{rc}\) 表示该节点的四邻域集合。

4. 评价指标

4.1 量化误差

代码首先根据所有样本的 BMU 计算量化误差(Quantization Error):

$$ \mathrm{QE}=\frac{1}{n}\sum_{i=1}^{n}\|z_i-w_{b(i)}\|_2 \tag{14} $$

该值越小,通常说明神经元权重对样本分布的逼近越好。

4.2 拓扑误差

当前代码把“第一 BMU”和“第二 BMU”是否在网格上相邻,作为拓扑保持的判断依据。若样本 \(z_i\) 的前两个 BMU 不满足曼哈顿距离为 1,则记为一次拓扑错误。于是拓扑误差为

$$ \mathrm{TE}=\frac{1}{n}\sum_{i=1}^{n}\mathbf{1}\!\left(\|r_{b_1(i)}-r_{b_2(i)}\|_1\neq 1\right) \tag{15} $$

这里的邻接定义是严格的上下左右相邻,不包括对角邻居。

5. 项目中的初始化与实现口径

5.1 random 初始化

init_method="random" 时,代码不会从标准正态分布初始化,而是按每个特征在当前训练数据中的最小值和最大值,在对应区间内均匀采样生成权重向量。

5.2 sample 初始化

init_method="sample" 时,程序会从样本矩阵中随机抽取节点初始权重。需要注意:

  1. 抽样使用 replace=True
  2. 因此同一个样本可能被多个节点重复选中。

5.3 训练样本抽取方式

每一轮迭代中,代码只随机抽取一个样本参与更新,而不是整批样本遍历一次后再统一更新。因此当前实现更接近在线式 SOM 训练,而不是批量式 SOM。

5.4 权重向量的尺度口径

权重向量 工作表中保存的是 codebook 本身。也就是说:

  1. standardize=True,则权重向量处在标准化后的特征空间;
  2. standardize=False,则权重向量处在原始特征空间。

当前代码不会把权重向量反变换回原始尺度,因此在报告中解释节点权重时必须先确认是否做过标准化。

6. 代码实现细节

6.1 BMU 映射结果

当前项目最终导出的 BMU映射 表包含:

  1. 样本名称列;
  2. bmu_row
  3. bmu_col
  4. bmu_index

其中 bmu_index 是按行优先顺序把二维网格展开后的节点索引。

6.2 U-Matrix 图与 BMU 散点图

项目会生成两张图:

  1. u_matrix.png
  2. bmu_scatter.png

其中:

  1. u_matrix.png 使用 viridis 色图显示 U-Matrix 热度;
  2. bmu_scatter.png 直接绘制样本落在 SOM 网格上的 BMU 位置;
  3. bmu_scatter.png 会调用 invert_yaxis(),因此图中的行坐标方向与数组索引方向相反。

6.3 原始数据表的口径

当前 raw_data 并不是整个上传文件的完整拷贝,而是

  1. 第 1 列样本 ID;
  2. 被选中的特征列

组成的子表。这一点与某些其他模块把完整原始表全部写入 Excel 的做法不同。

7. 算法流程

结合当前项目代码,SOM-自组织映射 的实际执行流程如下:

  1. 读取 .xlsx.xls.csv 文件,并校验首列样本名与后续数值特征。
  2. 在“特征选择”页从第 2 列及以后勾选参与训练的特征列。
  3. 在“方法设置”页设置 map_rowsmap_colsiterationslearning_ratesigmainit_methodstandardizerandom_state
  4. 取所选特征构造训练矩阵 \(X\),按需执行 z-score 标准化得到 \(Z\)。
  5. 在二维矩形网格上初始化全部节点权重向量。
  6. 重复执行随机抽样、BMU 搜索、指数衰减和高斯邻域更新,直到达到设定迭代次数。
  7. 计算每个样本的 BMU 位置、节点权重表和 U-Matrix。
  8. 计算量化误差与拓扑误差。
  9. 生成 u_matrix.pngbmu_scatter.png
  10. 导出 SOM_results_<时间戳>.xlsx,并在同目录下生成 SOM_plots_<时间戳>/ 图表目录。

8. 关键参数说明

8.1 map_rowsmap_cols

表示 SOM 网格的行数和列数。当前界面范围为 250。网格越大,表达能力越强,但也更容易出现节点稀疏。

8.2 iterations

表示训练迭代次数。当前界面范围为 105000,默认值为 500。该值过小会导致权重尚未充分收敛。

8.3 learning_rate

初始学习率,默认值为 0.5。代码会在训练过程中指数衰减,而不是固定不变。

8.4 sigma

初始邻域半径,默认值为 3.0。该值越大,早期更新会影响更宽的邻域;越小则更偏向局部微调。

8.5 init_method

当前支持:

  1. random
  2. sample

random 是按特征范围均匀采样,sample 是从现有样本中放回抽样初始化。

8.6 standardize

若勾选,则执行 z-score 标准化;不勾选则直接使用原始特征。由于 SOM 中的 BMU 搜索和权重更新都依赖欧氏距离,特征量纲差异较大时通常更建议开启标准化。

9. 输出结果与导出说明

9.1 Excel 工作表

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

  1. Parameters
  2. 原始数据
  3. 处理后数据
  4. BMU映射
  5. 权重向量
  6. U矩阵
  7. 评价指标
  8. Charts

其中:

  1. 处理后数据 为训练时实际使用的特征矩阵;
  2. 权重向量 保存 SOM 节点权重与其网格坐标;
  3. 评价指标 目前只有 quantization_errortopographic_error
  4. Charts 记录图表路径。

9.2 图表目录

当前图表会保存在结果目录下的

  1. SOM_plots_<时间戳>/u_matrix.png
  2. SOM_plots_<时间戳>/bmu_scatter.png

结果文件名则固定形如:

  1. SOM_results_<时间戳>.xlsx

10. 论文写作建议

10.1 方法描述模板

“本文采用自组织映射(SOM)方法对样本进行无监督结构学习。该方法首先在二维神经元网格上初始化节点权重,然后通过最佳匹配单元搜索和邻域协同更新,使高维样本在保留局部拓扑结构的前提下映射到低维网格空间。本文进一步结合 U-Matrix、样本 BMU 分布、量化误差和拓扑误差对映射效果进行分析。”

10.2 结果解释模板

结果部分可写为:BMU映射 可用于观察样本在 SOM 网格上的聚集位置,U矩阵 中高值区域通常对应簇间边界,低值区域通常对应簇内相似节点。若 quantization_error 越小,说明节点原型对样本表示越精确;若 topographic_error 越小,则通常说明样本局部拓扑关系保持得越好。

10.3 图表题注模板

  • 图 1 SOM U-Matrix 热力图。
  • 图 2 样本在 SOM 网格上的 BMU 映射散点图。
  • 表 1 SOM 样本 BMU 映射结果。
  • 表 2 SOM 节点权重向量与评价指标。

11. 实现说明与注意事项

  1. 当前模块只支持“首列样本名,后续列为数值特征”的数据结构。
  2. 若启用了标准化,权重向量 表中的数值位于标准化空间,不应直接按原始业务量纲解释。
  3. sample 初始化采用放回抽样,因此多个节点可能从同一样本开始。
  4. 拓扑误差中使用的是严格四邻域相邻判定,不包含对角邻接。
  5. 当前实现不会自动给节点再分簇,它输出的是 SOM 网格表示和 BMU 映射,而不是像 K-Means 那样直接给出若干类中心。

12. 单篇终审补充

12.1 图题与表题对齐建议

当前 SOM 模块的真实工作簿包含:

  • Parameters
  • 原始数据
  • 处理后数据
  • BMU映射
  • 权重向量
  • U矩阵
  • 评价指标
  • Charts

其中 BMU映射U矩阵 是正文最值得引用的两张核心表:前者解释样本落在哪个神经元节点,后者解释节点之间的相对边界结构。不要把 BMU映射 误写成“聚类标签表”,因为当前实现并没有直接输出 K 类标签。

图文件保存在结果目录下的 SOM_plots_<时间戳>/ 子目录,当前真实图名为:

  • u_matrix.png
  • bmu_scatter.png

因此图题建议分别写成“SOM U-Matrix 热力图”“SOM BMU 映射图”。这两张图的空间含义都是 SOM 网格空间,而不是原始特征前两维散点图。

12.2 终审说明

这篇文档最关键的工程事实,是 BMU映射 里的 bmu_rowbmu_colbmu_index 全都属于网格坐标表达,不是降维连续坐标。因此论文中若用这张表解释样本结构,应写“映射到网格节点的位置”,不要写成“连续二维嵌入坐标”。

另外,当前 权重向量 来自 codebook,在开启 standardize=True 时处于标准化空间。也就是说,U矩阵、BMU 位置和节点权重都共享预处理后的训练空间口径,不能直接按原始量纲解释业务数值大小。

12.3 全量强化补充

本次全量强化绑定的真实结果目录为 具体的算法3/聚类与降维/SOM-自组织映射/results/SOM-自组织映射分析结果_20260329_171346。目录内首个主结果文件为 SOM_results_20260329_171346.xlsx,实际工作表为 Parameters原始数据处理后数据BMU映射权重向量U矩阵评价指标Charts

该目录下真实图文件分成两组:SOM_plots_20260329_171346/u_matrix.pngSOM_plots_20260329_171346/bmu_scatter.png,以及二次生成的 SOM_plots_20260329_171347/u_matrix.pngSOM_plots_20260329_171347/bmu_scatter.png。与之对应,目录里还同时存在 SOM_results_20260329_171346.xlsxSOM_results_20260329_171347.xlsx。这说明当前目录不是单一静态快照,而是“主结果 + repro 再生成产物”并存。

复现脚本为 repro_som_自组织映射.py,脚本实际采用 INPUT_FILE = 'repro_inputs/som_自组织映射_repro_data.csv',而目录里还额外保留了 repro_inputs/som_ui_input.csv。因此这篇文档应如实写明:结果目录中既保存 UI 上传输入副本,也保存 repro 专用输入副本;主实验建议引用 171346 这组工作簿与图,而把 171347 这组视作在同目录再次运行后产生的复现实物。

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

  • 当前主结果目录应写作 具体的算法3/聚类与降维/SOM-自组织映射/results/SOM-自组织映射分析结果_20260329_171346
  • 正文应围绕 Parameters原始数据处理后数据BMU映射权重向量U矩阵评价指标Charts 来写。
  • 图证应对应 u_matrix.pngbmu_scatter.png,并把网格映射和 BMU 位置区分清楚。
  • 复现脚本应按 repro_som_自组织映射.py + repro_inputs/som_自组织映射_repro_data.csv 的口径说明,同时注意目录里也保留了 UI 输入副本。