30分钟学会SVD矩阵分解
SVD(Singular Value Decomposition)奇异值分解分解是机器学习中最重要的矩阵分解方法。
它能够将一个任意形状的矩阵分解成一个正交矩阵和一个对角矩阵以及另一个正交矩阵的乘积。
SVD分解具有非常深刻的几何含义。矩阵实际上对应着一种线性变换,一个矩阵作用到一个向量上,会得到一个新的向量。任何一个矩阵的操作效果可以分解成一次旋转,一次拉伸和维度改变,以及另外一次旋转三者作用效果的合成。
SVD分解通常用于数据压缩和数据降维。用于数据降维时,既可以对列降维,也可以对行降维,其中对列的降维等价于PCA的降维。
不仅如此,SVD算法还可以用于在声音和图像处理中剥离背景信号,在推荐算法中也经常出现它的身影。
一,SVD矩阵分解简介
SVD分解将任意矩阵分解成一个正交矩阵和一个对角矩阵以及另一个正交矩阵的乘积。
对角矩阵的对角元称为矩阵的奇异值,可以证明,奇异值总是大于等于0的。
当对角矩阵的奇异值按从大到小排列时,SVD分解是唯一的。
SVD分解有着非常深刻的几何含义。
矩阵实际上是对应着一种线性变换。一个矩阵作用到一个向量上,会得到一个新的向量。任何一个矩阵的操作效果可以分解成一次旋转,一次拉伸和维度改变,以及另外一次旋转三者作用效果的合成。
注意正交矩阵和作用到向量后是不会改变向量长度的,所以对应着旋转变换。
二,SVD分解的数学推演
三,SVD分解和数据压缩
假设 m = 10000,n = 8000,原来存储矩阵A需要存储8000万个数字,如果经过奇异值分解发现前100个奇异值贡献了99%的奇异值之和,于是可以近似只保留这100个奇异值及对应的左右奇异向量,那么只需要保留100+10000×100+100×8000= 180.01万个数字,只有原来的不到2.3%。
# 下面的范例示范SVD分解用于图片数据压缩。
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
import numpy as np
from matplotlib import pyplot as plt
from skimage import data
def compressBySVD(img,r):
u,s,vt = np.linalg.svd(img)
ur = u[:,0:r]
sr = s[0:r]
vtr = vt[0:r,:]
return (ur,sr,vtr)
def rebuildFromSVD(ur,sr,vtr):
img = ur@np.diag(sr)@vtr
return(img)
img = data.camera()/255.0
plt.figure(figsize=(10,8))
for i,r in enumerate([5,10,20,30,40,50,100,200],start = 1):
ur,sr,vtr = compressBySVD(img,r)
compress_ratio = (np.product(ur.shape) + len(sr) +
np.product(vtr.shape))/np.product(img.shape)
img_rebuild = rebuildFromSVD(ur,sr,vtr)
ax=plt.subplot(3,3,i)
ax.imshow(img_rebuild,cmap = "gray")
ax.set_title("r=%d"%r+", compress_ratio=%.2f"%compress_ratio)
ax.set_xticks([])
ax.set_yticks([])
ax = plt.subplot(3,3,9)
ax.imshow(img,cmap = "gray")
ax.set_title("r = 512, original image")
ax.set_xticks([])
ax.set_yticks([])
plt.show()
四,SVD分解和PCA降维
PCA降维可以看成是SVD分解的一个应用。PCA降维使用的变换矩阵恰好是SVD分解的右奇异矩阵。
实际上,由于SVD分解存在着无需通过计算特征值和特征向量的可并行的数值迭代计算算法,sklearn的PCA降维算法正是通过SVD分解计算的。
# 演示SVD用于PCA降维的计算
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
import numpy as np
from sklearn.decomposition import PCA
from matplotlib import pyplot as plt
from skimage import data
X = np.array([[-1.0, -3, -2], [-2, -1, -3], [-3, -2, -5], [2, 1, 3], [6, 1, 3], [2, 2, 3]])
pca = PCA(n_components= 2)
X_new = pca.fit_transform(X)
print("ndecomposition by pca:")
print("singular value:")
print(pca.singular_values_)
print("X_new:")
print(X_new)
print("ndecomposition by svd:")
U,S,Vt = np.linalg.svd(X-X.mean(axis = 0))
print("singular value:n",S[:2])
print("X_new:")
print(np.dot(X-X.mean(axis = 0),np.transpose(Vt)[:,0:2]))
# 注:降维结果中正负号的差异是因为PCA调整了SVD分解后的U和Vt符号以保持各列最大值取正
输出如下:
decomposition by pca:
singular value:
[11.31375337 2.89544001]
X_new:
[[ 3.23378083 1.06346839]
[ 3.88607412 -0.50763321]
[ 6.25267378 0.08479886]
[-3.50509914 -0.96584476]
[-6.02398361 1.89494314]
[-3.84344598 -1.56973242]]
decomposition by svd:
singular value:
[11.31375337 2.89544001]
X_new:
[[-3.23378083 -1.06346839]
[-3.88607412 0.50763321]
[-6.25267378 -0.08479886]
[ 3.50509914 0.96584476]
[ 6.02398361 -1.89494314]
[ 3.84344598 1.56973242]]
- 2017奇葩机器人大盘点:Sophia想生孩子,Atlas后空翻,贝佐斯骑“高达”……
- XmlSpy / XSD 以及 验证
- jQuery基础
- java与c#的反射性能比较
- 多迪技术总监揭秘:前端工程师主要做什么?前景怎么样?
- c#:Reflector+Reflexil 修改编译后的dll/exe文件
- testNG java.net.SocketException: Software caused connection abort: socket write error
- MyBatis.Net 学习手记
- 基于JavaScript 声明全局变量的三种方式详解
- 网页基础篇之如何制作简单的静态网页
- Mybatis.Net 整合 ODP.NET Managed
- 通过maven test 报org.apache.ibatis.binding.BindingException: Invalid bound statement
- 知道这几点,用微信小程序留住海量客户不是问题
- C#:DataTable映射成Model
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux硬链接与软链接原理及用法解析
- Linux通用java程序启动脚本代码实例
- 如何解决Ubuntu18.04循环登录/卡在开机界面/无法进入图形界面的问题
- CentOS7连接XShell与网络配置的方法
- 如何监控 Linux 服务器状态的方法
- Linux 文件系统的操作实现
- win10系统下安装superset的步骤
- Ubuntu下使用python3中的venv创建虚拟环境
- vsftpd配置虚拟用户登录的方法
- Linux 删除特殊字符文件名或目录的方法
- 详解Linux环境变量配置全攻略
- Linux lsof命令使用详解
- Ubuntu删除多余内核的方法
- 详解Linux下crontab的使用与注意事项
- Linux内核设备驱动之Linux内核基础笔记整理