当前位置: 首页 > news >正文

奇异值分解(singular value decomposition,SVD)

一、奇异值分解的定义

奇异值分解是将任意矩阵分解为三个特殊矩阵乘积的过程。对于 m×nm \times nm×n 矩阵 AAA,其奇异值分解表达式为:
A=UΣVTA = U\Sigma V^T A=UΣVT其中各矩阵的核心性质:

  • UUU(左奇异矩阵):m×mm \times mm×m 正交矩阵,满足 UTU=IU^T U = IUTU=I,列向量为左奇异向量

  • Σ\SigmaΣ(奇异值矩阵):m×nm \times nm×n 对角矩阵,对角线元素为非负奇异值(按降序排列),非对角线元素为 0;

  • VVV(右奇异矩阵):n×nn \times nn×n 正交矩阵,满足 VTV=IV^T V = IVTV=I,列向量为右奇异向量

二、奇异值分解的计算步骤(间接法求 UUU

以下通过示例详细说明仅通过 ATAA^T AATA 计算 SVD 的完整流程。

示例矩阵

选择 3×23 \times 23×2 矩阵 AAAm=3,n=2m=3, n=2m=3,n=2,含零行,贴近实际数据场景):
A=(200100)A = \begin{pmatrix} 2 & 0 \\ 0 & 1 \\ 0 & 0 \end{pmatrix}A=200010

步骤一:计算 ATAA^T AATA

AT=(200010)A^T = \begin{pmatrix} 2 & 0 & 0 \\ 0 & 1 & 0 \end{pmatrix} AT=(200100)M=ATA=(200010)(200100)=(4001)M = A^T A = \begin{pmatrix} 2 & 0 & 0 \\ 0 & 1 & 0 \end{pmatrix} \begin{pmatrix} 2 & 0 \\ 0 & 1 \\ 0 & 0 \end{pmatrix} = \begin{pmatrix} 4 & 0 \\ 0 & 1 \end{pmatrix}M=ATA=(200100)200010=(4001)

步骤二:求解 ATAA^T AATA 的特征值;

特征值是满足特征方程 det⁡(M−λI)=0\det(M - \lambda I) = 0det(MλI)=0λ\lambdaλ 值(III 为单位矩阵,det⁡(.)\det(.)det(.)表示求行列式),具体计算过程为:
det⁡(4−λ001−λ)=(4−λ)(1−λ)=0\det\begin{pmatrix} 4-\lambda & 0 \\ 0 & 1-\lambda \end{pmatrix} = (4-\lambda)(1-\lambda) = 0 det(4λ001λ)=(4λ)(1λ)=0解得特征值:λ1=4\lambda_1 = 4λ1=4λ2=1\lambda_2 = 1λ2=1按降序排列)。

步骤三:构造右奇异矩阵 VVV

该步骤利用 MMM 的特征向量来构造右奇异矩阵 VVV
特征向量需满足 (M−λI)v=0(M - \lambda I)\mathbf{v} = \mathbf{0}(MλI)v=0,且需单位化:

  • λ1=4\lambda_1 = 4λ1=4
    (000−3)(v11v12)=0⟹v12=0\begin{pmatrix} 0 & 0 \\ 0 & -3 \end{pmatrix} \begin{pmatrix} v_{11} \\ v_{12} \end{pmatrix} = \mathbf{0} \implies v_{12} = 0 (0003)(v11v12)=0v12=0取单位特征向量 v1=(10)\mathbf{v}_1 = \begin{pmatrix} 1 \\ 0 \end{pmatrix}v1=(10)

  • λ2=1\lambda_2 = 1λ2=1
    (3000)(v21v22)=0⟹v21=0\begin{pmatrix} 3 & 0 \\ 0 & 0 \end{pmatrix} \begin{pmatrix} v_{21} \\ v_{22} \end{pmatrix} = \mathbf{0} \implies v_{21} = 0 (3000)(v21v22)=0v21=0取单位特征向量 v2=(01)\mathbf{v}_2 = \begin{pmatrix} 0 \\ 1 \end{pmatrix}v2=(01)

因此,右奇异矩阵为:
V=(v1v2)=(1001)V = \begin{pmatrix} \mathbf{v}_1 & \mathbf{v}_2 \end{pmatrix} = \begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix}V=(v1v2)=(1001)

步骤四:构造奇异值矩阵 Σ\SigmaΣ

奇异值为特征值的平方根:σi=λi\sigma_i = \sqrt{\lambda_i}σi=λi,故 σ1=2\sigma_1 = 2σ1=2σ2=1\sigma_2 = 1σ2=1

Σ\SigmaΣm×nm \times nm×n 对角矩阵(非对角元素补 0):
Σ=(200100)\Sigma = \begin{pmatrix} 2 & 0 \\ 0 & 1 \\ 0 & 0 \end{pmatrix}Σ=200010

步骤五:间接法构造左奇异矩阵 UUU

核心公式:
ui=1σiAvi\mathbf{u}_i = \frac{1}{\sigma_i} A \mathbf{v}_iui=σi1Avi

1. 计算主左奇异向量(U1U_1U1

u1=1σ1Av1=12(200100)(10)=(100)\mathbf{u}_1 = \frac{1}{\sigma_1} A\mathbf{v}_1 = \frac{1}{2} \begin{pmatrix} 2 & 0 \\ 0 & 1 \\ 0 & 0 \end{pmatrix} \begin{pmatrix} 1 \\ 0 \end{pmatrix} = \begin{pmatrix} 1 \\ 0 \\ 0 \end{pmatrix}u1=σ11Av1=21200010(10)=100

u2=1σ2Av2=(200100)(01)=(010)\mathbf{u}_2 = \frac{1}{\sigma_2} A\mathbf{v}_2 =\begin{pmatrix} 2 & 0 \\ 0 & 1 \\ 0 & 0 \end{pmatrix} \begin{pmatrix} 0 \\ 1 \end{pmatrix}= \begin{pmatrix} 0 \\ 1 \\ 0 \end{pmatrix}u2=σ21Av2=200010(01)=010

因此主左奇异矩阵U1=(u1u2)=(100100)U_1 = \begin{pmatrix} \mathbf{u}_1 & \mathbf{u}_2 \end{pmatrix} = \begin{pmatrix} 1 & 0 \\ 0 & 1 \\ 0 & 0 \end{pmatrix}U1=(u1u2)=100010

2. 补充正交补向量(关键:区分 UUUVVV 的补充条件)

UUUm×mm \times mm×m 正交矩阵,需 mmm 个正交向量。当 m>rank(A)=rm > \text{rank}(A) = rm>rank(A)=r 时,需补充 m−rm - rmr 个向量(与 U1U_1U1 列向量正交且单位化)。

本例中,需为 UUU 补充 m−r=3−2=1m - r=3-2=1mr=32=1 个正交补向量:

u3=(x1x2x3)\mathbf{u}_3 = \begin{pmatrix} x_1 \\ x_2 \\ x_3 \end{pmatrix}u3=x1x2x3,需满足 u1Tu3=0\mathbf{u}_1^T \mathbf{u}_3 = 0u1Tu3=0u2Tu3=0\mathbf{u}_2^T \mathbf{u}_3 = 0u2Tu3=0,则有:
x1=x2=0x_1 = x_2 = 0 x1=x2=0则取单位向量 u3=(001)\mathbf{u}_3 = \begin{pmatrix} 0 \\ 0 \\ 1 \end{pmatrix}u3=001
因此正交补矩阵U2=(u3)=(001)U_2 = \begin{pmatrix} \mathbf{u}_3 \end{pmatrix} = \begin{pmatrix} 0 \\ 0 \\ 1 \end{pmatrix}U2=(u3)=001

3. 完整左奇异矩阵 UUU

U=(U1U2)=(100010001)U = \begin{pmatrix} U_1 & U_2 \end{pmatrix} = \begin{pmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{pmatrix}U=(U1U2)=100010001

验证分解结果

UΣVT=(100010001)(200100)(1001)=(200100)=AU\Sigma V^T = \begin{pmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} 2 & 0 \\ 0 & 1 \\ 0 & 0 \end{pmatrix} \begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix} = \begin{pmatrix} 2 & 0 \\ 0 & 1 \\ 0 & 0 \end{pmatrix} = AUΣVT=100010001200010(1001)=200010=A

分解成立。

三、奇异值分解的几何意义

矩阵 AAA 对向量的变换可拆解为三步:

  1. 旋转 / 反射VTV^TVT 将向量映射到标准正交基;

  2. 缩放Σ\SigmaΣ 沿坐标轴按奇异值比例缩放(奇异值为缩放因子);

  3. 旋转 / 反射UUU 将向量映射回原空间。

奇异值大小反映对应方向的 “重要性”,越大则该方向在变换中起主导作用。

四、奇异值分解的典型应用

  1. 数据降维

    保留前 kkk 个最大奇异值,用 UkΣkVkTU_k \Sigma_k V_k^TUkΣkVkT 近似原矩阵,实现高维数据压缩。例如 PCA 本质是通过 SVD 提取数据主成分。

  2. 图像压缩

    图像矩阵经 SVD 分解后,通过 A≈∑i=1kσiuiviTA \approx \sum_{i=1}^k \sigma_i \mathbf{u}_i \mathbf{v}_i^TAi=1kσiuiviT 还原,仅需存储 kkk 个奇异值及向量(k≪min⁡(m,n)k \ll \min(m,n)kmin(m,n)),大幅减少存储空间。

  3. 推荐系统

    对用户 - 物品评分矩阵做 SVD,提取潜在特征(如用户偏好、物品属性),预测未评分物品分值,提升推荐精度。

五、间接法求 UUU 的核心优势

  1. 计算效率

    m≫nm \gg nmn 时,ATAA^T AATAn×nn \times nn×n 矩阵(维度远小于 AATAA^TAATm×mm \times mm×m),特征值计算更高效。

  2. 正交性保障

    VVV 列向量正交,则 UUU 列向量自动正交(由线性变换性质保证),无需额外正交化处理。

通过间接法计算 SVD,既能简化复杂矩阵的分解过程,又能深刻理解左 / 右奇异向量与矩阵变换的内在联系,为实际工程应用提供坚实理论支撑。

六、SVD 实战

基本运算及数据压缩

在 SVD(奇异值分解)的矩阵压缩 / 近似场景中,k 表示保留的奇异值数量(取前 k 个最大的奇异值),其核心思想是:大的奇异值包含矩阵的主要信息,保留前 k 个奇异值即可用低秩矩阵近似原始矩阵。
SVD 的展开形式公式如下:
A=UΣVT=∑i=1rσi⋅ui⋅viTA = U \Sigma V^T = \sum_{i=1}^r \sigma_i \cdot u_i \cdot v_i^T A=UΣVT=i=1rσiuiviT当使用前 k 个奇异值进行近似时:
Ak=∑i=1kσi⋅ui⋅viTA_k = \sum_{i=1}^k \sigma_i \cdot u_i \cdot v_i^T Ak=i=1kσiuiviT

import numpy as np
from numpy import linalg as la
def compute_SVD(A):"""function: compute singular value decompositioninput: the matrix (m, n) you want to compute the SVDoutput:U (m, m),s (1, n), 注意这里为了节省空间只输出一维,后续需要转化VT (n, n)"""A = np.array(A) # 将输入的矩阵 A(以 Python 列表形式表示)转换为 NumPy 数组U, s, VT = la.svd(A)return U, s, VTif __name__ == '__main__':A = [[1, 1, 3, 6, 1], [5, 1, 8, 4, 2], [7, 9, 2, 1, 2]]print("原始矩阵:\n", A)# SVD奇异值分解U, s, VT = compute_SVD(A)Sigma = np.zeros((U.shape[0], VT.shape[0]))np.fill_diagonal(Sigma, s)  # 构造对角矩阵 Σprint("左奇异矩阵:\n", U)print("奇异值矩阵\n", Sigma)print("右奇异矩阵的转置\n", VT)# SVD重构验证A_reconstructed = U @ Sigma @ VT # 在 NumPy 中,@ 是矩阵乘法的运算符print("重构后的矩阵:\n", A_reconstructed)print('原矩阵与重构矩阵是否相同?', np.allclose(A, A_reconstructed))# SVD矩阵压缩(降维)for k in range(3, 0, -1):  # 3,2,1# 保留U的前k列,VT的前k行,前k个奇异值D = U[:, :k] @ Sigma[:k, :k] @ VT[:k, :]print('k=', k, "压缩后的矩阵:\n", np.round(D))  # round取整数

运行结果:
在这里插入图片描述

图片压缩

原理和上面的数据压缩一样。数字图像在计算机中以矩阵形式存储,每个像素对应矩阵中的一个元素。灰度图像的矩阵为二维,彩色图像的矩阵为三维(通常为高度、宽度和颜色通道)。RGBA 图像形状为 (高度, 宽度, 4),第四通道表示透明度(Alpha)。多光谱图像:形状可能为 (高度, 宽度, n),n 为波段数(如卫星图像)。下面用彩色图像来举例,我们可以分别从三种颜色通道中把二维矩阵提取出来。

import numpy as np
from PIL import Imagedef img_compress_compute1(img, percent):"""function: 根据奇异值数值总和的百分比对图片进行压缩:param img: 图片矩阵,这里只保留宽和高两维:param percent: 压缩比例:return: 压缩后图片矩阵"""# SVD计算U, s, VT = np.linalg.svd(img)Sigma = np.zeros(np.shape(img))Sigma[:len(s), :len(s)] = np.diag(s)# 压缩图片count = (int)(sum(s))*percent  # 保留奇异值总和k = -1SV_sum = 0while SV_sum <= count:k += 1SV_sum += s[k]img_compressed = U[:, :k] @ Sigma[:k, :k] @ VT[:k, :]# 纠正异常值# img_compressed [img_compressed  < 0] = 0# img_compressed [img_compressed > 255] = 255return np.rint(img_compressed).astype('uint8')def img_compress_compute2(img, percent):"""function: 根据奇异值个数的百分比对图片进行压缩:param img: 图片矩阵,这里只保留宽和高两维:param percent: 压缩比例:return: 压缩后图片矩阵"""# SVD计算U, s, VT = np.linalg.svd(img)Sigma = np.zeros(np.shape(img))Sigma[:len(s), :len(s)] = np.diag(s)# 压缩图片k = (int)(len(s))*percentimg_compressed = U[:, :k] @ Sigma[:k, :k] @ VT[:k, :]# 纠正异常值# img_compressed [img_compressed  < 0] = 0# img_compressed [img_compressed > 255] = 255return np.rint(img_compressed).astype('uint8')def img_compress(filename, percent):"""function: 压缩图片:param filename: 图片路径:param percent: 压缩比:return: null"""img = Image.open(filename, 'r')a = np.array(img)# 提取图片三通道矩阵R0 = a[:, :, 0]G0 = a[:, :, 1]B0 = a[:, :, 2]# 分别对三种颜色通道进行压缩R = img_compress_compute1(R0, percent)G = img_compress_compute1(G0, percent)B = img_compress_compute1(B0, percent)img_reconstructed = np.stack((R, G, B), axis=2)# 保存图片newfile = filename + str(percent*100) + '.png'Image.fromarray(img_reconstructed).save(newfile)# img.show()for i in range(10):print(i)img_compress('img/girl.jpg', i / 10)

对比结果(这里我们使用的图片压缩比为奇异值数值总和的百分比):
在这里插入图片描述
我们可以看到压缩比为60%以上在很大程度上已经还原了图片,这也说明,我们可以用更少的数据来存储图片。

参考
【1】【推荐算法】MF矩阵分解 – SVD、LFM、RSVD、SVD++.老弓的学习日记.哔哩哔哩
【2】【彻底搞懂】矩阵奇异值分解(SVD).牙非涯.知乎

http://www.dtcms.com/a/271514.html

相关文章:

  • 笔试——Day2
  • 单细胞入门(2)-经典案例分析
  • EPLAN 电气制图(六):结构盒与设备管理器核心概念(基础知识选看)
  • 脑电分析入门指南:信号处理、特征提取与机器学习
  • python 在运行时没有加载修改后的版本
  • windows server2019安全修复
  • 数据结构——深度优先搜索与广度优先搜索的实现
  • STM32-待机唤醒实验
  • 学习笔记(30):matplotlib绘制简单图表-绘制正弦波
  • Python的标准库之时间库(小白五分钟从入门到精通)
  • 【Netty+WebSocket详解】WebSocket全双工通信与Netty的高效结合与实战
  • 循环神经网络详解
  • cherryStudio electron因为环境问题无法安装解决方法或打包失败解决方法
  • NLP自然语言处理04 transformer架构模拟实现
  • Git版本控制完全指南:从入门到实战(简单版)
  • 【02】MFC入门到精通——MFC 手动添加创建新的对话框模板
  • 【PyTorch】PyTorch中torch.nn模块的全连接层
  • C++每日刷题 day2025.7.09
  • 备受期待的 MMORPG 游戏《侍魂R》移动端现已上线 Sui
  • RK3588 buildroot 解决软件包无法下载
  • 用户查询优惠券之缓存击穿
  • RAC-CELL(小区)处理
  • Ubuntu连接不上网络问题(Network is unreachable)
  • 国产航顺HK32F030M: 串口调试debug,重定向c库函数printf到串口,重定向后可使用printf函数
  • 记一次接口优化历程 CountDownLatch
  • C语言模块化编程思维以及直流电机控制(第四天)
  • 深度学习——损失函数
  • 【使用Flask基于PaddleOCR3.0开发一个接口 调用时报错RuntimeError: std::exception】
  • JVM调优实战指南:让Java程序性能飞升的奥秘
  • PanTS: The Pancreatic Tumor Segmentation Dataset