目录
老饼讲解:一步一步上手学习

【降维】一篇入门之-SVD 降维与应用

作者 : 老饼 发表日期 : 2025-12-17 00:09:18 更新日期 : 2026-05-10 16:08:46
老饼讲解-简单易懂,干货满满,爽过嗦螺!


SVD降维就是利用SVD分解,来对数据进行降维的一种方法,它可以在keep住数据信息的同时,使用更小的矩阵来表示数据,下面就让我们先来说说SVD降维的原理,再来展示一个具体的SVD降维例子、以及具体的代码实现,这样就会完全知道SVD降维到底是怎么一回事了!

一、SVD降维

1.1. SVD降维用来干什么

SVD降维,它的作用就是对矩阵降维:

SVD降维的效果

如图,把图片当作一个矩阵,那么降维后,仍然可以保持住矩阵中大部分的信息,但存储量却更少。

1.2. SVD分解

好了,SVD降维,固名思义就是使用SVD分解来进行降维,可能有些同学忘了SVD分解是什么了,我们不妨先来简单回忆下SVD分解。SVD分解呢,就是指将一个的矩阵A,分解为、 和 三个矩阵,如下 

其中,

 的酉矩阵      

 半正定对角矩阵

 的酉矩阵         

需要特别说明的是:

1. 对角元素一般由大到小排序,这样  和是唯一的。

2. 对角线上的元素称为A的奇异值。

1.3. SVD降维

好了,我们再来看SVD降维,想了解SVD降维,我们也不BB兜兜那么多理论,直接看下它的降维流程,马上就明白它是怎么一回事了,上车!为了不那么抽象,先来上个图:

SVD降维的过程

如图所示,使用SVD进行降维的流程如下:

1. SVD分解

对目标矩阵进行SVD分解,得到 三个矩阵,即:

2. 截取

忽略较小的奇异值,截取,从而获得近似矩阵 

也就是,如果的第k个奇异值较小,就截取,得到:

    

 其中

 的前k列  

          的前k行、前k列

的前k行

3. 降维存储 

用 替代进行存储

因为近似, 而可以拆解成进行记录

它们的记录量比直接记录A更加少,从而起到压缩的效果。

好了,这就是SVD降维了!如此简单!

二、SVD降维-例子解说

好了,为了更形象地了解SVD降维,肯定是拉个具体的例子来看看再好不过了。

就以图片为例,图片也是一个矩阵,但它很直观,下面我们就展示SVD降维是如何压缩图片的。

先来上张图片:

图片示例

上面的图片的像素为,如果直接存储,存储量为349*284=99116,下面我们用SVD对它进行降维,并展示取不同k值时的效果,具体代码如下:

'''
本代码展示如何用SVD对图片进行降维
本代码来自《老饼讲解-机器学习》 www.bbblearn.com
'''
import math 
import numpy as np
from numpy.linalg import svd
import matplotlib.pyplot as plt
from PIL import Image

# 读取图片
x     = Image.open("D:\\flower.png")                                  # 读取图片
U,S,V = svd(x, full_matrices=False)                                   # 对图片进行SVD分解
m,n   = x.size                                                        # 图片的大小
fig, axes = plt.subplots(2, 3,figsize=(8, 6))                         # 初始化画布
plt.subplots_adjust(wspace=0.2, hspace=0.3)                           # 调整子图之间的间隔
axes[0, 0].imshow(x,cmap="gray")                                      # 绘制原图 
axes[0, 0].set_title('k=full,(data='+str(m*n)+')')                    # 显示原图的大小
k_list = [100,50,25,10,5]                                             # 设置k的大小
for i in range(len(k_list)):                                          # 逐个k压缩图片
    k  = k_list[i]                                                    # 当前k
    Uk = U[:,:k]                                                      # 截取U前k列
    Sk = S[:k]                                                        # 截取S前k个元素
    Vk = V[:k,:]                                                      # 截取V前k行
    xk = Uk@np.diag(Sk)@Vk                                            # 计算压缩后的x
    data_num =  m*k+k+n*k                                             # 计算压缩后的数据量
    idx = (math.floor((i+1)/axes.shape[1]),(i+1)%axes.shape[1])       # 当前图片索引
    axes[idx].imshow(xk,cmap="gray")                                  # 绘制图片
    axes[idx].set_title('k='+str(k)+',(data='+str(data_num)+')')      # 显示图片数据量
plt.show()                                                            # 显示画布

 代码运行结果如下:

SVD降维的结果

可以看到,SVD降维的效果整体是不错的当k=50时,它的存储量为31700,只有原图的1/3,但图片质量与原图没太大差异。随着k 的取值越小,SVD降维后的所需存储的数据量越小,同时信息损失也在扩大,但不管k的取值如何,它总能在有效减少数据量的同时,保持住原图片的核心信息。

总结

SVD降维其实就是将矩阵分解成SVD,然后截取奇异值较大的部分来存储矩阵,这样既保留了矩阵大部分的信息,又能减少矩阵Size。用图像来理解它,可以最直观地看到它的效果,虽然存储量减少了,但却没有丢失核心信息。



图标 评论
添加评论