1、特征值分解(EVD)
实对称矩阵
一般矩阵
2、奇异值分解(SVD)
2.1 奇异值分解定义
2.2 奇异值求解
3、奇异值分解应用
3.1 纯数学例子
3.2例子2
3.3 在图像压缩中的应用
准备工具
下面的代码运行环境为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("../img/beauty.jpg")
print(img_eg.shape)
图片的大小是600×400×3
②奇异值分解
img_temp = img_eg.reshape(600, 400 * 3)
U,Sigma,VT = np.linalg.svd(img_temp)
我们先将图片变成600×1200,再做奇异值分解。从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(600,400,3)
# 取前120个奇异值
sval_nums = 120
img_restruct2 = (U[:,0:sval_nums]).dot(np.diag(Sigma[0:sval_nums])).dot(VT[0:sval_nums,:])
img_restruct2 = img_restruct2.reshape(600,400,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 = 120")
可以看到,当我们取到前面120个奇异值来重构图片时,基本上已经看不出与原图片有多大的差别。
4. SVD的一些性质
对于奇异值,它跟我们特征分解中的特征值类似,在奇异值矩阵中也是按照从大到小排列,而且奇异值的减少特别的快,在很多情况下,前10%甚至1%的奇异值的和就占了全部的奇异值之和的99%以上的比例。
也就是说,我们也可以用最大的k个的奇异值和对应的左右奇异向量来近似描述矩阵。
也就是说:
由于这个重要的性质,SVD可以用于PCA降维,来做数据压缩和去噪。也可以用于推荐算法,将用户和喜好对应的矩阵做特征分解,进而得到隐含的用户需求来做推荐。同时也可以用于NLP中的算法,比如潜在语义索引(LSI)。
5. SVD用于PCA
下面的X就是上面的A矩阵,这里是从别的blog那copy过来的,就不修改了,能理解就好。
总结
从上面的图片的压缩结果中可以看出来,奇异值可以被看作成一个矩阵的代表值,或者说,奇异值能够代表这个矩阵的信息。当奇异值越大时,它代表的信息越多。因此,我们取前面若干个最大的奇异值,就可以基本上还原出数据本身。
如下,可以作出奇异值数值变化和前部分奇异值和的曲线图,如下图所示
====================图片缺失==================
从上面的第1个图,可以看出,奇异值下降是非常快的,因此可以只取前面几个奇异值,便可基本表达出原矩阵的信息。从第2个图,可以看出,当取到前100个奇异值时,这100个奇异值的和已经占总和的95%左右。
最后,还有一点需要提到的是,如果自己想不调用np.linalg.svd
函数,手动实现奇异值分解的话,单纯利用第2小节的内容实现,有点不够,有个问题需要注意。这里暂时不多做讨论了,大家有兴趣可以看我下面分享的《SVD(奇异值分解)Python实现》,重点可以看看其中SVD算法实现。