SVD的全称Singular Value Decomposition,中文名是矩阵的奇异分解。它是一种常见的做矩阵降维处理的算法,在图像压缩和NLP算法中经常被用到。本文是我在编程过程中,对于数学中的SVD,numpy的svd方法,以及sklearn中的TruncatedSVD方法在实际应用中的一些理解和体会。

线性代数里的SVD

A是mxn的实数矩阵, 则A可以分解成以下的形式
A = U S V T A=USV^T A=USVT ,其中U是mxm的矩阵,S是mxn的对角阵,其主对角线上的每一个值被称为奇异值,V是nxn的矩阵。U和V都是酉矩阵(Unity Matrix),即 U T U = I , V T V = I U^TU=I, V^TV=I UTU=I,VTV=I。U称为左奇异矩阵,V称为右奇异矩阵
线代里求svd分解的方法主要用到了求特征向量和特征值得方法。
对于矩阵的特征值和特征向量性质,我们可知如果方阵 X m x m X_{mxm} Xmxm​如果存在m个线性无关的特征向量,可以做如下分解:
X = Q Λ Q − 1 X=Q \varLambda Q^{-1} X=QΛQ−1其中, Q Q Q是由其特征值组成的非奇异矩阵(即可逆), Λ \varLambda Λ是由其特征值组成的对角阵,其对角线上的每一个值对应于一个特征值。

A A T = U S V T ( U S V T ) T = U S V T V S T U T = U S S T U T AA^T=USV^T(USV^T)^T=USV^TVS^TU^T=USS^TU^T AAT=USVT(USVT)T=USVTVSTUT=USSTUT
同样的:
A T A = ( U S V T ) T U S V T = V S T U T U S V T = V S T S V T A^TA=(USV^T)^TUSV^T=VS^TU^TUSV^T=VS^TSV^T ATA=(USVT)TUSVT=VSTUTUSVT=VSTSVT
说明:
S S T 和 S T S SS^T和S^TS SST和STS都是对角阵,其对角线上的元素是奇异值的平方,但 S S T 和 S T S SS^T和S^TS SST和STS的维度是不同的, S S T SS^T SST是mxm的,而 S T S S^TS STS是nxn的。这是,我们对于A的奇异值个数应该是取m和n中较小的一个,也就是说多出来的值需要被舍弃,因为我们最终需要的 S S S是一个mxn的矩阵,主对角线上的奇异值的个数只能是min(m,n)。

此时,我们发现可以通过求 A A T AA^T AAT的特征值特征向量的方法来求U和S。(求特征值和特征向量的方法此处略过)
求得 A A T AA^T AAT的特征值,对其求开根号就可以得到我们需要的奇异值。特征向量组成的mxm的矩阵就是左奇异矩阵

但是,要注意的是当我们已经求得左奇异矩阵U后,再求右奇异矩阵V时不能再使用 A T A A^TA ATA了,因为对于同一个特征值特征向量是不唯一的,如果 u i u_i ui​是 A T A A^TA ATA对应于 λ i \lambda _i λi​特征向量,那么 − u i -u_i −ui​也是其特征向量。因为:
A ( u i ) = λ i ( u i ) , A ( − u i ) = λ i ( − u i ) A(u_i) = \lambda_i(u_i), A(-u_i) = \lambda_i(-u_i) A(ui​)=λi​(ui​),A(−ui​)=λi​(−ui​)
因此,如果我们使用 A T A A^TA ATA来求右奇异矩阵V,你很可能会遇到一组或几组特征向量的符号是反的,从而导致你求得的 U S V T USV^T USVT不等于 A A A。
那么为了确保得到正确的右奇异矩阵V,我们在求得左奇异矩阵U后,直接利用 A = U S V T , V T = S − 1 U − 1 A A=USV^T, V^T=S^{-1}U^{-1}A A=USVT,VT=S−1U−1A来得到对应的 V T V^T VT。此处, S − 1 U − 1 S^{-1}U^{-1} S−1U−1是伪逆阵,因为S和U都不是方阵,理论上不存在逆矩阵,但是伪逆阵依旧可以求得。

Numpy里的svd方法

在Numpy的linalg库里提供了现成的svd方法,可以直接分解出U,S,VT。
linalg.svd方法使用起来很简单,只要输入一个矩阵,三个返回值分别是左奇异矩阵,对应的奇异值列表,和右奇异矩阵的转置。而且奇异值是按照大小顺序排列好的。这也是推荐使用的方法,效率比较高。
python代码如下:

import numpy as np
A=np.asarray([[6,1,9],[4,9,9],[4,0,6],[7,4,7]],dtype=np.float32)
U, S, VT=np.linalg.svd(A,full_matrices=1)
print('A:')
print(A)
print('U:')
print(U)
print('S:')
print(S)
print('VT:')
print(VT)
output=========
A:
[[6. 1. 9.][4. 9. 9.][4. 0. 6.][7. 4. 7.]]
U:
[[-0.50626906 -0.5132768  -0.33109968][-0.61136554  0.73364755 -0.29256487][-0.32459939 -0.43574965 -0.28201245][-0.51435304 -0.09181746  0.85161481]]
S:
[20.4062792   6.38531027  2.1935318 ]
VT:
[[-0.50876229 -0.39526907 -0.76480278][-0.39634588  0.89616339 -0.19950219][ 0.7642453   0.20162724 -0.61259741]]

这里要提一下的是full_matrices这个参数,默认值是1,即如果输入矩阵是mxn的,则返回的左奇异矩阵是mxm的,右奇异矩阵是nxn的。
如果full_matrices=0, 则返回的左奇异矩阵是mxk的,右奇异矩阵是kxn的,而k是m和n中较小的那个。画个表格来看就比较明白了。

左奇异矩阵 右奇异矩阵
m>n mxn nxn
m<n mxm mxn

当m>n时,左奇异矩阵是mxn的,右奇异矩阵是xn的。
那如果我不想用这个现成的方法,能不能从求特征值得方法来求分解呢,也是可以的,而且计算结果是一样的。下面直接上代码:

import numpy as np
A=np.asarray([[6,1,9],[4,9,9],[4,0,6],[7,4,7]],dtype=np.float32)
#先求左奇异矩阵和对应的奇异值
#np.linalg.eigh是求特征值和特征向量的方法
#第一个返回值是特征值列表
#第二个返回值是特征向量组成的矩阵
EIGENV_U,U = np.linalg.eigh(np.dot(A,A.T))
#np.linalg.eigh的返回值不会像svd方法一样按特征值大小排好序,所以必须自己排序
#获得对奇异值的排序的位置
EIGENV_U_sort_idx = np.argsort(EIGENV_U)[::-1]
#重新对奇异值按大小排序
EIGENV_U = EIGENV_U[EIGENV_U_sort_idx]
#对奇异矩阵里的特征向量也进行一样的顺序调整
U=U[:,EIGENV_U_sort_idx]
#对拍好序的特征值求平方差,得到奇异值
S = np.sqrt(EIGENV_U)
#这里有个细节处理需要注意
#因为AxAT是mxm的,我们会得到m个特征值,如果m>n,我们实际上只需要取前n个
#因为求逆阵必须是满秩的,因此先对对角方阵求逆,
#再将其填入一个nxm的矩阵中,A是mxn的,此处逆阵的行列数记得反一下
S= np.diag(S[:min(A.shape[0],A.shape[1])])
S= np.linalg.inv(S)
S_diag = np.zeros((A.shape[1],A.shape[0]))
S_diag[:min(A.shape[0],A.shape[1]),:min(A.shape[0],A.shape[1])] = S
VT=np.dot(np.dot(S_diag,np.linalg.inv(U)),A)
print('A:')
print(A)
print('U:')
print(U)
print('S:')
print(S)
print('VT:')
print(VT)
output=========
A:
[[6. 1. 9.][4. 9. 9.][4. 0. 6.][7. 4. 7.]]
U:
[[-0.50626904  0.5132768  -0.3310997  -0.6087788 ][-0.61136556 -0.7336475  -0.29256487  0.0489822 ][-0.3245994   0.43574965 -0.28201243  0.79071265][-0.51435304  0.09181746  0.85161483  0.04198474]]
S:
[20.406279  6.38531   2.193532  0.      ]
VT:
[[-0.5087623  -0.39526909 -0.76480279][ 0.39634593 -0.89616334  0.19950226][ 0.76424524  0.20162717 -0.61259742]]

从求得结果来看和直接用svd是一样的,但是VT中第二行的值是正负相反的。但是如果我们验证一下结果,算一下 U S V T USV^T USVT的结果正好也等于 A A A。这其实也算是分解成功的,只是有些情况下,向量值会正负相反。

sklearn里的TruncatedSVD方法

最后,我想说一下sklearn里的TruncatedSVD方法,这个方法创建是设置参数n_components可以直接实现降维,他会舍弃你设置的维度以后的所有数值。
比如说n_components=2,那么他返回给你的就是 U S US US 得到的矩阵的前两列。
来看个代码例子就更清楚了。

from sklearn.decomposition import TruncatedSVD
svd = TruncatedSVD(n_components=2)
M_reduced=svd.fit_transform(A)
print('sklearn TruncatedSVD')
print(M_reduced)
#U是之前用svd直接求得的左奇异矩阵
#S_diag是由奇异值构成的mxn对角矩阵
print('np svd U x S_diag, get left 2 cols')
print(np.dot(U,S_diag))[:,:2])
output=========
sklearn TruncatedSVD
[[10.331068  -3.27743  ][12.475696   4.6845646][ 6.6238675 -2.7823956][10.496031  -0.5862823]]np svd U x S_diag, get left 2 cols
[[-10.33106704  -3.27743167][-12.47569588   4.68456701][ -6.62386549  -2.78239667][-10.49603137  -0.58628297]]

你看,值是不是一模一样。使用TruncatedSVD可以直接提取到我们想保留的最重要的特征维度,舍弃不需要的数据,提升计算性能,在处理大量数据是非常的有用。

参考文章
[1] 奇异值分解原理和应用(SVD和TruncatedSVD)
[2]使用Python求解特征值、特征向量及奇异值分解(SVD)

[数学基础知识] 线代里的svd, numpy 的svd以及sklearn的TruncatedSVD相关推荐

  1. 机器学习数学基础之线代篇——线性代数python手册(建议收藏)

    提到线性代数,又不得不吐槽国内教材了,学起来真的是实力劝退.有多少跟着国内教材学完线性代数课程后,知道线性代数是什么,它到底是干什么的? 事实上如果你后面想做科研.想研究机器学习.深度学习,你会发现处 ...

  2. AI 数学基础知识-方向导数与梯度、范数矩阵、SVD分解、PCA、凸函数

    原课程链接 自己的课程笔记,方便自己查漏补缺.想补充数学预备知识的友友,建议去看原视频. 相比于考研数学,这里更注重理解,而不是强调计算能力. 数分 方向导数和梯度 之后学梯度下降算法需要,考研时没学 ...

  3. 机器学习数学基础:线代(3)

    2.3.4 求解线性方程组的算法 下面简单的介绍一些Ax=b 的解的求解方法.现在我们假设是有解的,如果没有解就要求助于近似解,这需要线性回归的方法以后再说. 再特别的例子中,我们可以定义可逆矩阵A, ...

  4. 分段概率密度矩估计_考研数学:高数、线代、概率3科目知识框架梳理

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 首先要确保常考题型,常考知识点非常熟练.下面从高等数学.线性代数.概率统计三个模块进行阐述. 高等数学部分 1.函数的极 限;数列的极 限;无穷小及阶的问 ...

  5. 下载 线代 薛威_考研数学:选择了深巷子里的数学大神老师,我放心

    对于不打算报班考研的学生最头疼的估计就是数学了,没打算考研的时候就听说宇哥,汤神,而我义无反顾的选择了新东方老师薛威.在大二下学期听了薛老师的高数选修课(蹭的学长的班)就深深喜欢上了这个老师.三遍,已 ...

  6. 遗忘线代知识,导致应力第三不变量对应力的导数求不出来

    线代性质: 1.伴随矩阵的性质--矩阵行列式关于矩阵求导得到伴随矩阵: 2.伴随矩阵的性质--伴随矩阵等于行列式和矩阵逆阵相乘 附 矩阵微积分维基百科链接

  7. 数学基础(高数、线代、概率论、统计学等等)

    此文章只作为个人学习笔记,不会面面俱到,完整学习还请多看看书和视频吧,个人理解如果有错误希望指出,共同学习进步. 机器学习 高数.线代和概率论是黄海广博士的知乎帖子,只是做总结,具体知识点参考课本和视 ...

  8. 数学之美3 - 线代篇

    线代篇 向量空间模型 文本检索 文本聚类 矩阵 线性回归 PCA主成分分析 奇异值分解 33 | 线性代数:线性代数到底都讲了些什么? 向量和向量空间 标量(Scalar).它只是一个单独的数字,而且 ...

  9. 知乎热议:高数、线代应该成为计算机专业学习的重心吗?

    点击上方,选择星标或置顶,不定期资源大放送! 阅读大概需要5分钟 Follow小博主,每天更新前沿干货 作为一名计算机专业的学生,你觉得求学期间哪门课程最重要? 你又将哪门课程作为学习的重中之重呢? ...

最新文章

  1. 金税接口调用实例 java_Java 常见面试题
  2. 面向对象分析和设计的几个关键步骤_(豁然开朗)《面向对象分析与设计》读书笔记 (4)- 分类...
  3. Redis分布式锁 Spring Schedule实现任务调度
  4. ASP.NET的错误处理机制
  5. php sorcket_PHP: Sockets - Manual
  6. 启动php-fpm服务器_无服务器冷启动不是问题-这就是为什么(对于大多数应用程序)...
  7. 实例讲解webpack的基本使用第二篇
  8. CentOS 6.2 虚拟机 mail邮件信息: crash:[abrt] full crash report
  9. R语言空间权重矩阵columbus及画图
  10. Font shape `TU/ptm/m/n' undefined(Font) using `TU/lmr/m/n' instead
  11. 微信小程序之授权登录的实现(button按钮)
  12. 岩板铺地好吗_岩板铺客厅地面好吗 比800*800的瓷砖更美观又大气?
  13. 虚拟机软件有哪些?分别有哪些作用?
  14. 2019年程序员最值得选择的100家互联网公司排名
  15. ffmpeg 3.2版本播放ts流正常,但是录制成为MP4的文件播放黑屏
  16. 各类牛B电影,暑假慢慢看完
  17. vue项目对接pad端——混合开发总结
  18. 使命召唤8联机找不到服务器,使命召唤8怎么联机 使命召唤8联机方法简介
  19. 2020HYS-MISC-你觉得这个是什么文件
  20. C# 窗口实现Win7简单屏幕泡泡保护程序 和实现聊天窗口震动

热门文章

  1. 题解-弹飞绵羊 (HNOI2015)
  2. 传统电商的流量焦虑症与突围战
  3. pxcook使用(量尺寸)+盒子模型+残缺新浪导航栏
  4. 把CSMA/CD、Token Bus、Token Ring说清楚
  5. 2021年危险化学品经营单位安全管理人员考试题库及危险化学品经营单位安全管理人员理论考试
  6. android 仿快递步骤_【干货速递,建议收藏】Android 流式布局,一篇搞定
  7. Ubuntu工作环境配置
  8. 网络中立:YouTube联名上书
  9. 2021-12-04-java-easyPoi-map导出
  10. Hadoop的一些认识--------我与Hadoop不得不说的故事