1 SVD分解介绍
之前用特征值来进行对角化的时候,被对角化的矩阵一定要是方阵,但是SVD的话,非方阵也是可以的。
矩阵Σ对角线上的元素都是大于等于0的
我们可以改变U,V的一些行和列,来达到Σ对角线上的元素越来越小
所以rank(A)就是Σ中对角线元素不为零的数量
如果把Σ中全零的部分抹掉,然后U和V中全零对应的行和列也去掉,那么乘积结果还是等于A
如果我们多抹掉一些(比如多抹掉一行),把Σ中非零的一部分也抹掉了,结果肯定不等于A了,但是是所有rank为k-1的部分中最接近于A的,接近的意思是两个矩阵相减的结果拉成一条向量,这个向量的norm最小
2 SVD的应用:图像压缩
2.1可以用小一点的维度来复原一张相似的图
2.1 SVD分解的应用2:文档-词项矩阵的奇异值分解
参考了 奇异值分解的揭秘(二):降维与奇异向量的意义 - 知乎 (zhihu.com)
给定一个大小为7×5的矩阵A,A的前4行表示来源于CS的文档,后3行表示来源于医学(MD)的文档,A的各列分别对应着5个单词,在矩阵中,每个元素的数值表示单词在相应文档中出现的频数。
我们使用numpy 对其进行SVD分解
import numpy as np
A = [[1, 1, 1, 0, 0],
[2, 2, 2, 0, 0],
[1, 1, 1, 0, 0],
[5, 5, 5, 0, 0],
[0, 0, 0, 2, 2],
[0, 0, 0, 3, 3],
[0, 0, 0, 1, 1]]
[U, s, v] = np.linalg.svd(A)
[U, s, v]
'''
[[-0.1796053 , 0. , 0.97298719, -0.07270854, -0.05034883,-0.10906282,-0.03635427],
[-0.3592106 , 0. , 0.05552004, 0.49265053, -0.13571796,0.73897579, 0.24632526],
[-0.1796053 , 0. , 0.02776002, 0.03887713, 0.98065351,0.05831569, 0.01943856],
[-0.89802651, 0. , -0.22235746, -0.19029393, -0.13177375,-0.28544089,-0.09514696],
[ 0. , -0.53452248, 0. , 0.71428571, 0. ,-0.42857143,-0.14285714],
[ 0. , -0.80178373, 0. , -0.42857143, 0. ,0.35714286, -0.21428571],
[ 0. , -0.26726124, 0. , -0.14285714, 0. ,-0.21428571,0.92857143]]),
[9.64365076e+00, 5.29150262e+00, 7.52989891e-16, 0.00000000e+00,0.00000000e+00]),
array([[-0.57735027, -0.57735027, -0.57735027, -0. , -0. ],
[-0. , -0. , -0. , -0.70710678, -0.70710678],
[ 0.81649658, -0.40824829, -0.40824829, 0. , 0. ],
[ 0. , 0. , 0. , -0.70710678, 0.70710678],
[ 0. , -0.70710678, 0.70710678, 0. , 0. ]])]
'''
奇异值主要是前两项,所以我们使用前两项的U,V矩阵和对应的奇异值对齐进行近似
U[:,:2] @ np.diag(s[:2]) @ v[:2,:] ''' array([[1., 1., 1., 0., 0.], [2., 2., 2., 0., 0.], [1., 1., 1., 0., 0.], [5., 5., 5., 0., 0.], [0., 0., 0., 2., 2.], [0., 0., 0., 3., 3.], [0., 0., 0., 1., 1.]]) '''
近似结果和原来的是一样的
我们可以很明显地发现,左右奇异向量u和v已经有了明显的语义信息:第一行/列 表示的内容是CS 相关的 ,第二行/列 表示的内容是MD相关的。
此时,我们使用第一行V,第一列U和第一个奇异值就可以得到CS相关的特征矩阵;使用第二行V,第二列U和第二个奇异值就可以得到MD相关的特征矩阵
U[:,:1] @ np.diag(s[:1]) @ v[:1,:] ''' array([[1., 1., 1., 0., 0.], [2., 2., 2., 0., 0.], [1., 1., 1., 0., 0.], [5., 5., 5., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]]) '''
U[:,1:2] @ np.diag(s[1:2]) @ v[1:2,:] ''' array([[0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 2., 2.], [0., 0., 0., 3., 3.], [0., 0., 0., 1., 1.]]) '''
3 SVD求解
这里中间的和可以消掉,是因为V和U是正交矩阵
和都是对称矩阵,那么我们就可以对其进行特征值分解(要变成标准正交基的那种,也就是特征值分解了之后,还要对特征空间的基进行施密特正交化)
然后Σ对角线的值就是或的特征值的开方