SVD与CUR自我总结
参考:https://www.cnblogs.com/endlesscoding/p/10033527.html https://blog.csdn.net/WangWeb1998/article/details/114376298
1. SVD(奇异值分解)
-
定义:
有一个的实数矩阵A,我么想要把它分解成如下形式:
其中和均为单位正交阵,即有和,称为左奇异矩阵,称为右奇异矩阵,仅在主对角线上有值,我们称它为**
奇异值
**,其它元素均为0。上面矩阵的维度分别为。一般的有如下形式:
- 奇异值求解
-
在图像压缩中的应用:
-
读取图片
%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)
图片大小为600x400x3
-
奇异值分解
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个奇异值来重构图片时,基本上已经看不出与原图片有多大的差别。
-
-
总结:
从上面的图片的压缩结果中可以看出来,奇异值可以被看作成一个矩阵的代表值,或者说,奇异值能够代表这个矩阵的信息。**当奇异值越大时,它代表的信息越多。**因此,我们取前面若干个最大的奇异值,就可以基本上还原出数据本身。
2. CUR(矩阵分解)
提到矩阵分解,相信大家最熟悉的一定是SVD分解,但是SVD分解有两个缺点:
-
可解释性较差:对于SVD分解,大家通常的理解应该是,左奇异向量以及右奇异向量分别张成了原始矩阵所在的列空间以及行空间,但是对于原始矩阵而言,并没有较强的可解释性。
-
太过密集:就算原始矩阵是一个稀疏矩阵,该矩阵所分解而成的U、V矩阵仍然是高度密集的,这在某些应用场景下是难以接受的。
与SVD相比 -
CUR分解的可解释性大大加强了
- CUR矩阵分解:
对于一个矩阵 A ,我们能否将它分解为 只包含 A 中的一些行和列的组合呢?
更具体地讲,对于一个秩 k 矩阵 A ,如果我们选择其中 k 列张成矩阵 A 的列空间,选择其中 k 行张成矩阵 A 的行空间,那么我们也应该能够通过组合这些线性映射来恢复原矩阵。
为了更加直观的理解记忆CUR矩阵分解,大家可以看下面这张图
图中红色代表所选择的列,蓝色代表所选择的行,U就是这些行和列的交叉点,在图中用紫色表示。
从图中我们可以看出,CUR分解就像是找出了一个矩阵的 “骨架” ,这个骨架体现了这个矩阵最主要的信息。
文章出处登录后可见!