正在加载中...

展开本页目录
算法教程NMF-非负矩阵分解

NMF-非负矩阵分解

No.128 · 在线教程

非负矩阵分解(Non-negative Matrix Factorization, NMF)是一类把非负数据矩阵分解为两个低秩非负矩阵乘积的方法。与 PCA、SVD 等允许正负抵消的分解不同,NMF 在分解过程中要求各因子均保持非负,因此往往更容易得到“部分加和式”的可解释结果…

NMF-非负矩阵分解

1. 方法概述

非负矩阵分解(Non-negative Matrix Factorization, NMF)是一类把非负数据矩阵分解为两个低秩非负矩阵乘积的方法。与 PCA、SVD 等允许正负抵消的分解不同,NMF 在分解过程中要求各因子均保持非负,因此往往更容易得到“部分加和式”的可解释结果,常用于主题提取、成分分析和特征压缩。

本项目中的 NMF-非负矩阵分解 模块并不是自写乘法更新或坐标下降算法,而是对 sklearn.decomposition.NMF 的工程化封装。当前代码支持:

  1. nndsvdnndsvdanndsvdarrandom 四种初始化方式;
  2. cdmu 两种求解器;
  3. frobeniuskullback-leibleritakura-saito 三种 beta_loss
  4. alpha_Walpha_Hl1_ratio 正则化参数;
  5. nonestandardminmax 三种特征预处理方式;
  6. 输出样本低维表示 \(W\)、成分载荷矩阵 \(H\)、重构矩阵与误差指标。

设共有 \(n\) 个样本、\(p\) 个被选中的特征。记非负输入矩阵为

$$ X=(x_{ij})_{n\times p},\quad x_{ij}\ge 0 \tag{1} $$

当前模块约定第 1 列为样本/对象标识列,后续被勾选的特征列必须全部非负。

2. 数据要求与预处理

2.1 数据约束

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

  1. 数据不能为空;
  2. 至少包含两列,即第 1 列对象名称和至少 1 列指标;
  3. 第 1 列对象名称必须唯一;
  4. 第 2 列及以后必须可以转成数值;
  5. 特征列不能含空值或无穷值;
  6. 特征列不能出现负值;
  7. 特征列不能是常数列;
  8. 至少选择 1 个特征;
  9. 真正开始计算时,还要求 \(r\le \min(n,p)\),其中 \(r=\texttt{n\_components}\)。

2.2 预处理方式

程序支持三种预处理方式:

  1. none
  2. standard
  3. minmax

其中最需要注意的是 standard 的具体实现。代码并没有使用普通的均值中心化标准化,而是使用

  1. StandardScaler(with_mean=False)

因此其变换形式为

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

而不是常见的 \((x_{ij}-\mu_j)/\sigma_j\)。这一步的直接目的,是在缩放特征的同时保持非负性,避免因为减去均值而破坏 NMF 的非负约束。

normalization="minmax" 时,程序执行

$$ 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.3 符号说明

符号 含义
\(n\) 样本数量
\(p\) 特征维数
\(r\) 分解秩 n_components
\(Z\) 进入 NMF 的非负特征矩阵
\(W\) 样本低维表示矩阵
\(H\) 成分载荷矩阵
\(\hat Z\) 重构矩阵
\(\mathcal{L}\) NMF 优化目标

3. 核心数学模型

3.1 基本分解形式

NMF 的目标是把非负矩阵 \(Z\) 分解为两个低秩非负矩阵乘积:

$$ Z\approx WH \tag{6} $$

其中

$$ W\in\mathbb{R}_{+}^{n\times r},\qquad H\in\mathbb{R}_{+}^{r\times p} \tag{7} $$

在项目结果中:

  1. W 工作表对应样本的低维表示;
  2. H 工作表对应各成分在原始特征上的载荷。

3.2 重构矩阵

分解完成后,代码按

$$ \hat Z=WH \tag{8} $$

构造重构矩阵,并导出为 Reconstruction 工作表。

3.3 目标函数与损失

项目把 solverbeta_loss 等参数直接传给 sklearn.decomposition.NMF。从一般形式看,可理解为在非负约束下最小化

$$ \min_{W\ge 0,H\ge 0}\ \mathcal{L}(Z,WH)+\Omega(W,H) \tag{9} $$

其中 \(\mathcal{L}\) 是由 beta_loss 决定的拟合损失,\(\Omega(W,H)\) 则由 alpha_Walpha_Hl1_ratio 决定的正则项组成。

3.4 正则化结构

从参数意义上,项目支持对 \(W\) 与 \(H\) 分别加入惩罚项:

$$ \Omega(W,H)=\alpha_W\,\Psi(W)+\alpha_H\,\Psi(H) \tag{10} $$

其中 \(\Psi(\cdot)\) 的具体稀疏/平滑结构由 l1_ratio 控制。当

$$ 0\le \texttt{l1\_ratio}\le 1 \tag{11} $$

时:

  1. 越接近 1,越偏向 L1 型稀疏约束;
  2. 越接近 0,越偏向 L2 型平滑约束。

4. 项目中的参数修正规则

4.1 n_components 上限

fit() 中,若用户设置的分解秩超过

$$ \min(n,p) \tag{12} $$

程序会直接报错,而不是自动截断。

4.2 solverbeta_loss 的联动

当前代码对 solverbeta_loss 做了实际修正:

  1. solver != "mu"beta_loss != "frobenius",则会强制改写为

$$ \texttt{beta\_loss}\leftarrow \texttt{"frobenius"} \tag{13} $$

  1. solver == "mu"beta_loss != "frobenius"init == "nndsvd",则会自动改写为

$$ \texttt{init}\leftarrow \texttt{"nndsvda"} \tag{14} $$

这两个规则并不是教科书通用结论,而是当前项目为了匹配 sklearn.NMF 使用约束而加入的实现细节,文档中需要明确。

5. 评价指标

5.1 重构均方误差

项目在得到 \(W\) 与 \(H\) 后,会根据重构矩阵 \(\hat Z=WH\) 计算重构均方误差:

$$ \mathrm{MSE}=\frac{1}{np}\sum_{i=1}^{n}\sum_{j=1}^{p}(z_{ij}-\hat z_{ij})^2 \tag{15} $$

代码将其记录为

  1. reconstruction_mse

并同时写入 Stats 表与 Parameters 表。

5.2 残差与迭代次数

项目还会从 sklearn.NMF 模型对象中读取:

  1. n_iter_
  2. reconstruction_err_

其中 reconstruction_err_ 被记录为

$$ \text{residual}=\texttt{reconstruction\_err\_} \tag{16} $$

这两个值共同用于判断模型是否在设定迭代次数内稳定收敛。

6. 代码实现细节

6.1 非负性检查发生在预处理前

当前代码会先检查原始特征矩阵中是否存在负值:

$$ \exists\,x_{ij}<0 \Rightarrow \text{直接报错} \tag{17} $$

因此,项目不接受“先上传含负值数据,再依赖预处理把它变为非负”的工作流。

6.2 WH 的导出结构

代码中的结果组织为:

  1. W:样本数 × 成分数,首列保留样本 ID;
  2. H:成分数 × 特征数,首列为 Component1Component2 等成分名称;
  3. Reconstruction:与输入特征矩阵同形,并在首列保留样本 ID。

6.3 图表内容

当前实现会额外生成 nmf_components.png,图中包含两部分:

  1. 左图是 \(W\) 的前两列散点图;
  2. 右图是 \(H\) 的热力图。

当 \(W\) 只有 1 个成分时,左图会退化为单轴散点图。

7. 算法流程

结合当前项目代码,NMF-非负矩阵分解 的实际执行流程如下:

  1. 读取 .xlsx.xls.csv 文件,并校验首列样本 ID 是否唯一。
  2. 对第 2 列及以后检查:是否可转数值、是否含空值/无穷值、是否存在负值、是否为常数列。
  3. 在“特征选择”页勾选参与分解的特征列。
  4. 在“方法与参数”页设置 n_componentsinitsolverbeta_lossalpha_Walpha_Hl1_ratiomax_itertolnormalizationrandom_state
  5. normalization 选项执行不处理、with_mean=False 标准化或 Min-Max 缩放。
  6. 根据 solver/beta_loss/init 的组合关系,按代码规则自动修正不兼容参数。
  7. 调用 sklearn.decomposition.NMF.fit_transform() 得到 \(W\),并读取 components_ 作为 \(H\)。
  8. 计算重构矩阵 \(WH\)、重构 MSE、n_iter_reconstruction_err_
  9. 生成 WHReconstructionStatsParameters 与组件图。
  10. 导出 Excel 文件 nmf_results_<时间戳>.xlsx,并自动生成复现脚本。

8. 关键参数说明

8.1 n_components

分解秩,也就是隐因子数量。当前要求:

$$ 1\le r\le \min(n,p) \tag{18} $$

8.2 init

当前支持:

  1. nndsvd
  2. nndsvda
  3. nndsvdar
  4. random

其中 nndsvd 系列通常更适合稀疏、可解释的非负分解。

8.3 solver

当前支持:

  1. cd
  2. mu

cd 是坐标下降路线,mu 是乘法更新路线。两者与 beta_loss 存在代码中的兼容性修正规则。

8.4 beta_loss

当前支持:

  1. frobenius
  2. kullback-leibler
  3. itakura-saito

但只有当 solver="mu" 时,后两者才真正有效;否则会被自动回退到 frobenius

8.5 alpha_Walpha_Hl1_ratio

这一组参数控制正则化强度与稀疏性。当前验证要求

$$ 0\le \texttt{l1\_ratio}\le 1 \tag{19} $$

8.6 max_itertol

分别控制最大迭代次数和收敛阈值,默认值为 200 和 \(10^{-4}\)。

8.7 normalization

支持:

  1. none
  2. standard
  3. minmax

其中 standard 并不会减去均值,而是采用 with_mean=False 的缩放方式,以保持非负性。

9. 输出结果与导出说明

9.1 Excel 工作表

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

  1. RawData
  2. Features
  3. W
  4. H
  5. Reconstruction
  6. Stats
  7. Parameters
  8. Charts

其中:

  1. RawData 保存原始完整数据;
  2. Features 保存选中的原始特征矩阵,不含首列样本 ID;
  3. W 保存样本低维表示;
  4. H 保存成分载荷;
  5. Reconstruction 保存重构矩阵;
  6. Charts 记录 nmf_components.png 的路径。

9.2 图表文件

当前代码会在结果目录中直接生成:

  1. nmf_components.png

其内容为:

  1. W 的前两成分散点图;
  2. H 的热力图。

10. 论文写作建议

10.1 方法描述模板

“本文采用非负矩阵分解(NMF)方法对非负数据矩阵进行低秩表示。设原始特征矩阵为 \(X\),在满足非负约束的条件下,将其分解为样本低维表示矩阵 \(W\) 与成分载荷矩阵 \(H\),使得 \(X\approx WH\)。与允许正负抵消的线性分解方法不同,NMF 更适合从非负数据中提取可解释的局部成分。本文进一步利用重构均方误差、迭代次数和残差项评估分解效果。”

10.2 结果解释模板

结果部分可写为:W 的每一行可理解为样本在各隐因子上的权重分布,H 的每一行则可理解为某个潜在成分在各原始特征上的载荷模式。若 reconstruction_mse 较小,通常说明当前成分数下的分解已较好重构原始矩阵,因此可据此解释潜在结构与原始特征之间的关系。

10.3 图表题注模板

  • 图 1 NMF 样本低维表示散点图与成分载荷热力图。
  • 表 1 NMF 分解得到的样本低维表示矩阵 \(W\)。
  • 表 2 NMF 成分载荷矩阵 \(H\) 及重构误差结果。

11. 实现说明与注意事项

  1. NMF 对输入非负性要求严格,原始特征中只要存在负值,当前模块就会直接报错。
  2. standard 预处理不是普通的中心化标准化,而是 with_mean=False 缩放;不要在论文里误写成减均值后的 z-score。
  3. beta_losssolver 并非任意组合都有效,当前代码会自动修正不兼容设置。
  4. WH 的解释依赖成分数 n_components,成分数过小会损失结构,过大则可能削弱压缩与可解释性。
  5. 当前图中的 W 仅展示前两成分,若成分数大于 2,图像不能代表全部低维结构。

12. 单篇终审补充

12.1 图题与表题对齐建议

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

  • RawData
  • Features
  • W
  • H
  • Reconstruction
  • Stats
  • Parameters
  • Charts

其中 WH 是论文中最应该单独引用的两张核心表,Reconstruction 则适合放在附录或结果复核部分使用。不要把 W 写成“主成分得分矩阵”,也不要把 H 写成“特征向量矩阵”,因为当前实现是 NMF 分解而不是 PCA/SVD。

当前 save_to_excel() 直接在结果目录下生成图文件,真实主图名为:

  • nmf_components.png

历史结果目录里可能还能看到带时间戳的旧图名,但当前实现已固定使用 nmf_components.png。因此论文图题建议写成“NMF 样本表示与成分载荷联合图”,不要根据旧文件残留写成多个图名版本。

12.2 终审说明

这篇文档最需要明确的工程事实是:Reconstruction 是基于当前参与分解的非负特征矩阵直接重构得到的结果表,不包含首列样本 ID 之外的额外业务字段。因此如果论文想展示“原始业务表复原”,需要自己明确说明这里只是特征子矩阵重构,而不是整表重建。

另外,当前 repro 脚本已经采用 repro_inputs/... 相对路径,结果目录中可见如 repro_inputs/nmf_sample.xlsx 的输入副本引用。可复现性可以按新框架写,但图表路径当前仍是结果目录本地文件路径,不应和 repro 输入路径混为一种口径。

12.3 全量强化补充

本篇终审补充绑定的真实算法目录为 具体的算法3/聚类与降维/NMF-非负矩阵分解,本次采用的代表性结果目录为 具体的算法3/聚类与降维/NMF-非负矩阵分解/results/NMF-非负矩阵分解分析结果_20260322_040637

该目录当前只保留了一份工作簿:

  • nmf_results_20260322_040637.xlsx

实测工作表为:

  • RawData
  • Features
  • W
  • H
  • Reconstruction
  • Stats
  • Parameters
  • Charts

从页名和维度看,这一轮结果已经足够支撑论文中的三层解释:Features 是实际参与分解的非负特征矩阵,W 是样本成分权重矩阵,H 是成分载荷矩阵,Reconstruction 则是对参与分解特征矩阵的重构结果。这里仍需避免把 W/H 写成 PCA 的“得分/载荷”术语。

当前目录中的真实图文件只有一张:

  • 具体的算法3/聚类与降维/NMF-非负矩阵分解/results/NMF-非负矩阵分解分析结果_20260322_040637/nmf_components.png

因此这一轮真实图证据只能写成“样本前两成分表示与成分载荷热力图的联合图”。若正文需要更多图形,只能另外生成,不能把磁盘上并不存在的重构误差曲线或成分贡献折线图写进本篇说明。

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

  • 具体的算法3/聚类与降维/NMF-非负矩阵分解/results/NMF-非负矩阵分解分析结果_20260322_040637/repro_nmf_非负矩阵分解.py
  • 具体的算法3/聚类与降维/NMF-非负矩阵分解/results/NMF-非负矩阵分解分析结果_20260322_040637/repro_inputs/nmf_sample.xlsx

脚本中明确写成 INPUT_FILE = 'repro_inputs/nmf_sample.xlsx'OUTPUT_DIR = '.'OUTPUT_FILE = 'nmf_results_20260322_040637.xlsx'。这意味着当前 repro 默认会把结果写回与主结果同名的工作簿,磁盘上不会同时保留一份独立命名的 repro 工作簿。因此这一篇不能写成“主结果与 repro 输出并存”,更准确的口径应是“目录内已完成相对路径化复现,但 repro 默认覆盖同名结果文件”。

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

  • 当前主结果目录应写作 具体的算法3/聚类与降维/NMF-非负矩阵分解/results/NMF-非负矩阵分解分析结果_20260322_040637
  • 正文应围绕 FeaturesWHReconstructionStatsParametersCharts 来写。
  • 图证应对应 nmf_components.png,并把成分矩阵与重构结果的关系写清。
  • 复现脚本应按 repro_nmf_非负矩阵分解.py + repro_inputs/nmf_sample.xlsx 的口径说明。