正在加载中...

展开本页目录
算法教程SVD-奇异值分解

SVD-奇异值分解

No.134 · 在线教程

奇异值分解(Singular Value Decomposition, SVD)是一类最基础也最重要的矩阵分解方法。对于任意实矩阵,它都可以分解为左奇异向量、奇异值和右奇异向量的乘积形式,因此常用于降维、压缩、噪声过滤和潜在结构提取。

SVD-奇异值分解

1. 方法概述

奇异值分解(Singular Value Decomposition, SVD)是一类最基础也最重要的矩阵分解方法。对于任意实矩阵,它都可以分解为左奇异向量、奇异值和右奇异向量的乘积形式,因此常用于降维、压缩、噪声过滤和潜在结构提取。

本项目中的 SVD-奇异值分解 模块并不是调用 sklearn.decomposition.TruncatedSVD,而是直接基于 numpy.linalg.svdscipy.sparse.linalg.svds 实现完整 SVD / 截断 SVD 计算。根据当前代码,它具有以下特点:

  1. 固定要求第 1 列为样本 ID,后续列为数值特征;
  2. 支持特征标准化 standardize 与单独中心化 center
  3. 支持 autofullarpack 三种求解器策略;
  4. 输出低维嵌入、奇异值、方差贡献率、成分载荷和重构误差;
  5. n_components 超过最大秩时会自动截断到最大可用秩;
  6. 当使用截断 SVD 时,会在结果中额外标注方差贡献率的估计口径。

设共有 \(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.pyindicators_widget.pydata_validator.pycore/svd_calculator.py 的实现,模块对输入数据的真实要求如下:

  1. 数据不能为空;
  2. 至少包含两列,即第 1 列对象名称和至少 1 列特征;
  3. 第 2 列及以后必须是数值型列;
  4. 特征列不能含空值;
  5. 至少选择 1 个特征列;
  6. n_components 必须不小于 1;
  7. svd_solver 仅支持 autofullarpack

需要特别注意的是,SVD 模块对数据校验采取的是“部分提醒、部分阻断”的策略:

  1. 第 1 列样本名称重复只会给出提示,不会阻断;
  2. 常数列也只会给出提示,不会阻断;
  3. 但非数值列和空值会直接报错。

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。

2.3 仅中心化

standardize=Falsecenter=True 时,程序不会缩放标准差,而只执行减均值:

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

standardize=Falsecenter=False,则直接令

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

记最终进入 SVD 的矩阵为

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

2.4 符号说明

符号 含义
\(n\) 样本数量
\(p\) 特征维数
\(r\) 矩阵秩或最大可分解维度
\(k\) 实际保留的分解维数
\(U\) 左奇异向量矩阵
\(\Sigma\) 奇异值对角矩阵
\(V^\top\) 右奇异向量转置矩阵
\(s_i\) 第 \(i\) 个奇异值
\(T\) 低维嵌入矩阵
\(\hat Z\) 低秩重构矩阵

3. 核心数学模型

3.1 奇异值分解

对预处理后的矩阵 \(Z\),SVD 可写为

$$ Z=U\Sigma V^\top \tag{6} $$

其中:

  1. \(U\in\mathbb{R}^{n\times r}\)
  2. \(\Sigma=\operatorname{diag}(s_1,s_2,\ldots,s_r)\)
  3. \(V^\top\in\mathbb{R}^{r\times p}\)

并且奇异值满足

$$ s_1\ge s_2\ge \cdots \ge s_r\ge 0 \tag{7} $$

3.2 低维嵌入

当前项目保留前 \(k\) 个奇异值及对应向量,并把样本低维表示定义为

$$ T=U_k\Sigma_k \tag{8} $$

这正对应代码中的

  1. embedding = U[:, :k] * s[:k]

因此 低维嵌入 工作表保存的是样本在前 \(k\) 个奇异方向上的坐标。

3.3 成分载荷

程序导出的 成分载荷 表来自

$$ V_k^\top=V^\top_{1:k,:} \tag{9} $$

它反映每个保留成分在原始特征上的方向载荷。

3.4 低秩重构

当前代码用前 \(k\) 个成分对数据做重构:

$$ \hat Z=U_k\Sigma_k V_k^\top \tag{10} $$

并进一步基于 \(Z\) 与 \(\hat Z\) 计算重构误差。

4. 方差贡献率与评价指标

4.1 奇异值方差贡献率

代码用奇异值平方近似各成分的方差信息:

$$ v_i=s_i^2 \tag{11} $$

当使用完整 SVD 时,方差贡献率按

$$ \rho_i=\frac{v_i}{\sum_{j=1}^{r}v_j} \tag{12} $$

计算,累计贡献率为

$$ R_k=\sum_{i=1}^{k}\rho_i \tag{13} $$

4.2 截断 SVD 下的特殊口径

当使用 arpack 且只求出前 \(k\) 个奇异值时,代码仍然按

$$ \rho_i=\frac{v_i}{\sum_{j=1}^{k}v_j} \tag{14} $$

计算“方差贡献率”。这意味着:

  1. 当前贡献率只是在前 \(k\) 个奇异值内部做归一化;
  2. explained_variance_sum 会等于 1;
  3. 代码会额外给出说明文字:仅基于前 k 个奇异值估计方差贡献(使用截断 SVD)

因此,在 arpack 截断模式下,结果中的累计贡献率不能和完整 SVD 的全量贡献率完全等价。

4.3 重构均方误差

项目当前的核心评价指标为

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

代码将其记录为 reconstruction_mse

5. 项目中的求解器逻辑

5.1 full 求解器

svd_solver="full" 时,代码直接调用 numpy.linalg.svd(X, full_matrices=False) 计算完整 SVD。

5.2 arpack 求解器

svd_solver="arpack" 时,代码调用 scipy.sparse.linalg.svds(X, k=k, v0=v0) 计算截断 SVD,并在结果返回后按奇异值从大到小重新排序。

若设置了 random_state,程序会用它生成 v0 初始向量。

5.3 auto 求解器

svd_solver="auto" 时,代码按如下规则选择:

  1. max_rank >= 300k <= max_rank // 2,则自动转为 arpack
  2. 否则使用完整 SVD。

5.4 n_components 的自动截断

设最大可用秩为

$$ r=\min(n,p) \tag{16} $$

则程序实际保留维数为

$$ k=\min(\texttt{n\_components},\, r) \tag{17} $$

若用户输入的 n_components 超过最大秩,代码不会报错,而是自动截断并写日志警告。

6. 代码实现细节

6.1 standardize 会强制中心化

界面层中,当勾选 standardize 时:

  1. center 会被自动勾选;
  2. center 复选框会被禁用。

这与底层代码的逻辑一致,因为标准化本身已经包含减均值操作。

6.2 原始数据表的口径

当前 原始数据 工作表并不是整个上传文件的完整拷贝,而是:

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

组成的子表。

6.3 图表生成规则

当前模块会生成三类图表:

  1. singular_values.png
  2. cum_variance.png
  3. embedding_2d.png

其中 embedding_2d.png 只有在

  1. k >= 2

时才会生成。

7. 算法流程

结合当前项目代码,SVD-奇异值分解 的实际执行流程如下:

  1. 读取 .xlsx.xls.csv 文件,并校验首列样本名与后续数值特征。
  2. 在“特征选择”页从第 2 列及以后勾选参与分解的特征列。
  3. 在“方法设置”页设置 n_componentsstandardizecentersvd_solverrandom_state
  4. 按参数设置对特征矩阵执行标准化、中心化或不处理。
  5. 根据 svd_solver 选择完整 SVD 或截断 SVD,并在必要时自动切换或截断维数。
  6. 计算样本低维嵌入 \(U_k\Sigma_k\)、成分载荷 \(V_k^\top\)、奇异值及方差贡献率。
  7. 基于前 \(k\) 个成分重构矩阵并计算 reconstruction_mse
  8. 生成奇异值曲线、累计贡献率曲线和二维嵌入散点图。
  9. 导出 SVD_results_<时间戳>.xlsx,并在同目录下生成 SVD_plots_<时间戳>/ 图表目录。

8. 关键参数说明

8.1 n_components

目标降维维度,界面范围为 150。若超过最大秩,程序会自动调整为 min(n,p)

8.2 standardize

是否执行 z-score 标准化。启用后会自动包含中心化操作。

8.3 center

仅在 standardize=False 时可自由控制。勾选后执行减均值,不勾选则直接对原始特征矩阵做 SVD。

8.4 svd_solver

当前支持:

  1. auto
  2. full
  3. arpack

full 给出完整奇异值序列,arpack 更适合大矩阵下只求前若干个成分。

8.5 random_state

主要影响 arpack 路线下初始向量 v0 的生成;对完整 SVD 本身影响很小。

9. 输出结果与导出说明

9.1 Excel 工作表

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

  1. 原始数据
  2. 处理后数据
  3. 低维嵌入
  4. 奇异值
  5. 方差贡献
  6. 成分载荷
  7. 评价指标
  8. 参数设置
  9. 方差贡献说明
  10. 图表清单

其中 方差贡献说明 只在截断 SVD 估计贡献率时出现。

9.2 图表目录

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

  1. SVD_plots_<时间戳>/singular_values.png
  2. SVD_plots_<时间戳>/cum_variance.png
  3. SVD_plots_<时间戳>/embedding_2d.png

结果文件名为:

  1. SVD_results_<时间戳>.xlsx

10. 论文写作建议

10.1 方法描述模板

“本文采用奇异值分解(SVD)方法对样本特征矩阵进行分解。通过对预处理后的矩阵进行 SVD,将数据表示为左奇异向量、奇异值和右奇异向量的乘积形式,并提取前若干个主导奇异成分构造低维嵌入。本文进一步结合奇异值分布、累计方差贡献率和重构误差评估降维效果。”

10.2 结果解释模板

结果部分可写为:低维嵌入 表反映样本在保留奇异方向上的坐标,成分载荷 表则反映每个保留成分在原始特征上的方向权重。若 reconstruction_mse 越小,通常说明前 \(k\) 个奇异成分对原矩阵的重构越充分;若使用 arpack,则还应说明方差贡献率是基于前 \(k\) 个奇异值估计的。

10.3 图表题注模板

  • 图 1 SVD 奇异值分布曲线。
  • 图 2 SVD 累计方差贡献率曲线。
  • 图 3 SVD 二维嵌入散点图。
  • 表 1 SVD 低维嵌入结果。
  • 表 2 SVD 奇异值、方差贡献率与重构误差结果。

11. 实现说明与注意事项

  1. 当前模块对重复样本名和常数列只给提示,不会阻断计算。
  2. 若不开启标准化且不开启中心化,SVD 将直接作用于原始特征矩阵,结果会明显受量纲影响。
  3. n_components 超过最大秩时会被自动截断,不会报错中止。
  4. arpack 模式下的方差贡献率是截断估计值,不能机械等同于完整 SVD 的全量贡献率。
  5. 低维嵌入 使用的是 \(U_k\Sigma_k\),而不是单独的 \(U_k\)。

12. 单篇终审补充

12.1 图题与表题对齐建议

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

  • 原始数据
  • 处理后数据
  • 低维嵌入
  • 奇异值
  • 方差贡献
  • 成分载荷
  • 评价指标
  • 参数设置
  • 方差贡献说明(仅在存在说明时出现)
  • 图表清单

其中 奇异值方差贡献成分载荷 是这篇文档最适合在论文中配套引用的三张方法结果表,低维嵌入 则适合正文展示样本表示结果。不要把 成分载荷 写成 PCA 的“主成分系数矩阵”,当前口径应保持在 SVD 分解框架内。

图文件保存在结果目录下的 SVD_plots_<时间戳>/ 子目录,当前实现真实输出:

  • singular_values.png
  • cum_variance.png
  • embedding_2d.png(仅当保留维度不少于 2 时生成)

因此图题建议分别写成“SVD 奇异值曲线”“SVD 累计贡献率曲线”“SVD 二维嵌入散点图”。若本次运行只保留 1 个成分,则第三张图不会生成,正文中不应保留它的占位描述。

12.2 终审说明

这篇文档最关键的工程事实,是当前 低维嵌入 使用的是 \(U_k\Sigma_k\),而不是只导出 \(U_k\)。因此若论文里需要解释样本在主导奇异方向上的坐标,这张表可以直接用;但如果要讨论左奇异向量本身的正交结构,则不能把它与 低维嵌入 混为一谈。

另外,方差贡献说明 只在 variance_note 存在时才写入工作簿,主要用于提醒截断 SVD 情况下的贡献率解释限制。因此这张表不是每次运行都会出现,论文中应按实际导出结果决定是否引用。

12.3 全量强化补充

本次全量强化绑定的真实结果目录为 具体的算法3/聚类与降维/SVD-奇异值分解/results/SVD-奇异值分解_RealForward_20260322_045532。代表性结果文件可采用 SVD_results_20260322_045534.xlsx,其实际工作表为 原始数据处理后数据低维嵌入奇异值方差贡献成分载荷评价指标参数设置图表清单。由此可见,当前真实工作簿并未生成 方差贡献说明,正文引用时应按实际导出结果表述。

同一结果目录下真实图文件位于 SVD_plots_20260322_045534/,包括 singular_values.pngcum_variance.pngembedding_2d.png。论文中可分别写为“SVD 奇异值分布图”“SVD 累计方差贡献率图”“SVD 二维嵌入散点图”。

复现脚本为 repro_svd_奇异值分解.py,当前输入口径为 INPUT_FILE = 'repro_inputs/svd_sample.csv'。脚本会优先按结果目录下的 repro_inputs 解析输入,并重新输出同构 xlsx。因此这篇文档现在已经具备“结果目录 + repro_inputs 相对路径 + 重建输出”三件套,应在论文附录中按这一真实口径描述。

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

  • 当前主结果目录应写作 具体的算法3/聚类与降维/SVD-奇异值分解/results/SVD-奇异值分解_RealForward_20260322_045532
  • 正文应围绕 原始数据处理后数据低维嵌入奇异值方差贡献成分载荷评价指标参数设置图表清单 来写。
  • 图证应对应 singular_values.pngcum_variance.pngembedding_2d.png,并把截断维数和重构/嵌入含义区分开。
  • 复现脚本应按 repro_svd_奇异值分解.py + repro_inputs/svd_sample.csv 的口径说明。