SVD(奇异值分解)

https://www.cnblogs.com/endlesscoding/p/10033527.html

奇异值分解(SVD)在数据降维中有较多应用。

一、特征值分解

实对称矩阵

在理角奇异值分解之前,需要先回顾一下特征值分解,如果矩阵A是一个m×m的实对称矩阵(即 A = A T A=A^{^{T}} A=AT),那么它可以被分解成如下的形式:
在这里插入图片描述其中Q为标准正交阵,即有 Q = Q T Q=Q^{T} Q=QT,Σ为对角矩阵,且上面的矩阵的维度均为m×m。 λ i \lambda_{i} λi称为特征值, q i q_{i} qi是Q(特征矩阵)中的列向量,称为特征向量。

一般矩阵

上面的特征值分解,对矩阵有着较高的要求,它需要被分解的矩阵A为实对称矩阵,但是现实中,我们所遇到的问题一般不是实对称矩阵。那么当我们碰到一般性的矩阵,即有一个m×n的矩阵A,它是否能被分解成上面的式(1-1)的形式呢?当然是可以的,这就是我们下面要讨论的内容。

2、奇异值分解(SVD)

2.1 奇异值分解定义

有一个m×n的实数矩阵A,我们想要把它分解成如下的形式
在这里插入图片描述在这里插入图片描述对于奇异值分解,我们可以利用上面的图形象表示,图中方块的颜色表示值的大小,颜色越浅,值越大。对于奇异值矩阵Σ,只有其主对角线有奇异值,其余均为0。

2.2奇异值求解

正常求上面的U,V,Σ不便于求,我们可以利用如下性质
在这里插入图片描述可以看到式(2-2)与式(1-1)的形式非常相同,进一步分析,我们可以发现 A A T AA^{^{T}} AAT A T A A^{^{T}}A ATA也是对称矩阵,那么可以利用式(1-1),做特征值分解。利用式(2-2)特征值分解,得到的特征矩阵即为U;利用式(2-3)特征值分解,得到的特征矩阵即为V;对 λ λ T \lambda\lambda^{^{T}} λλT λ T λ \lambda^{^{T}}\lambda λTλ中的特征值开方,可以得到所有的奇异值。

3、奇异值分解应用#

3.1 纯数学例子

在这里插入图片描述分别对上面做特征值分解,得到如下结果

U = 
[[-0.55572489, -0.72577856,  0.40548161],
 [-0.59283199,  0.00401031, -0.80531618],
 [-0.58285511,  0.68791671,  0.43249337]]
 
V = 
[[-0.18828164, -0.01844501,  0.73354812,  0.65257661,  0.06782815],
 [-0.37055755, -0.76254787,  0.27392013, -0.43299171, -0.17061957],
 [-0.74981208,  0.4369731 , -0.12258381, -0.05435401, -0.48119142],
 [-0.46504304, -0.27450785, -0.48996859,  0.39500307,  0.58837805],
 [-0.22080294,  0.38971845,  0.36301365, -0.47715843,  0.62334131]]

奇异值Σ=Diag(18.54,1.83,5.01)

3.2 在图像压缩中的应用#

准备工具#

下面的代码运行环境为python3.6+jupyter5.4

SVD(Python)#

这里暂时用numpy自带的svd函数做图像压缩。
①读取图片

%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
 
img_eg = mpimg.imread("pic1.jpg")
print(img_eg.shape)

图片大小为(687, 960, 3)

②奇异值分解

img_temp = img_eg.reshape(687, 960*3)
U,Sigma,VT = np.linalg.svd(img_temp)

我们先将图片变成687*2880,再做奇异值分解。从svd函数中得到的奇异值sigma它是从大到小排列的

③取前部分奇异值重构图片

# 取前60个奇异值
sval_nums = 60
img_restruct1 = (U[:,0:sval_nums]).dot(np.diag(Sigma[0:sval_nums])).dot(VT[0:sval_nums,:])
img_restruct1 = img_restruct1.reshape(687, 960, 3)
 
# 取前300个奇异值
sval_nums = 300
img_restruct2 = (U[:,0:sval_nums]).dot(np.diag(Sigma[0:sval_nums])).dot(VT[0:sval_nums,:])
img_restruct2 = img_restruct2.reshape(687, 960, 3)

将图片显示出来看一下,对比下效果

fig, ax = plt.subplots(1,3,figsize = (24,32))
 
ax[0].imshow(img_eg)
ax[0].set(title = "src")
ax[1].imshow(img_restruct1.astype(np.uint8))
ax[1].set(title = "nums of sigma = 60")
ax[2].imshow(img_restruct2.astype(np.uint8))
ax[2].set(title = "nums of sigma = 300")

在这里插入图片描述可以看到,当我们取到前面300个奇异值来重构图片时,基本上已经看不出与原图片有多大的差别。

总结

从上面的图片的压缩结果中可以看出来,奇异值可以被看作成一个矩阵的代表值,或者说,奇异值能够代表这个矩阵的信息。当奇异值越大时,它代表的信息越多。因此,我们取前面若干个最大的奇异值,就可以基本上还原出数据本身。

如下,可以作出奇异值数值变化和前部分奇异值和的曲线图,如下图所示

import numpy as np
import matplotlib.pyplot as plt
  
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
axes[0].plot(Sigma)
axes[1].plot(Sigma.cumsum())

在这里插入图片描述从上面的第1个图,可以看出,奇异值下降是非常快的,**因此可以只取前面几个奇异值,便可基本表达出原矩阵的信息。**从第2个图,可以看出,当取到前100个奇异值时,这100个奇异值的和已经占总和的95%左右。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值