svd降维 python案例_SVD 降维体现在什么地方?

这篇回答节选自我在专栏

1.行压缩数据降维

我们直接从矩阵$A$的奇异值分解:

入手,分析如何进行行压缩数据降维。

等式两侧同时乘以左奇异矩阵的转置:

,得到:

,重点是左侧的

,我们把矩阵

记作

维列向量并排放置的形式,我们展开来看:

这是我们刚讲过的基变换方法,很熟悉了吧,

原本使用的是默认的一组基向量

,我们通过上面的基变换,将其用

这一组标准正交基来表示,由于这一组标准正交基本质上也是由协方差对称矩阵

得到,因此将各列做基变换后,数据分布从行的角度来看就彼此无关了。

此时,我们可以把每一列看作是一个样本,各行是不同的特征,各行彼此无关,我们可以按照熟悉的方法,选择最大的$k$个奇异值对应的$k$个标准正交向量,形成行压缩矩阵:

通过

,就实现了列向量从

维到

维的数据降维,完成了主成分的提取。

2.列压缩数据降维

奇异值分解的精彩之处就在于他可以从两个维度进行数据降维,分别提取主成分,前面介绍的是对行进行压缩降维,那么下面我们来说说如何对列进行压缩降维。

还是牢牢抓住

进行启发,我们对式子两边同时乘以右奇异矩阵

,得到

,我们还是聚焦等式的左侧:

我们将其整体进行转置的预处理,得到

,我们把矩阵

记作

那么同样的道理:

类比上面的行压缩过程,在

中,我们从大到小取前

个特征值对应的标准正交特征向量,就构成了另一个压缩矩阵:

。很明显,通过

就能实现将

矩阵的各列由

维压缩到

维。而大家不要忘了,

的列不正是

矩阵的各行吗。

由此,各行向量的维数由

压缩到了

维,实现了列压缩的数据降维。

3.对矩阵整体进行数据压缩

这里我们不谈按行还是按列,我们从矩阵的整体视角,再谈一个数据压缩的方式,我们的思路有点类似级数的概念,将一个

的原始数据矩阵

分解成若干个同等维度矩阵乘以各自权重后相加的形式。这个如何实现?

依旧从奇异值分解的表达式入手,

,我们展开成完整的矩阵形式:

,这里

这里展开就得到了:

不难发现,每一个

的结果都是一个等维的

形矩阵,并且他们彼此之间正交,前面的

则是对应矩阵的权重,

,依序代表了“重要性”的程度,因此我们可以按照主成分贡献率的最低要求,选择前$k$项进行叠加,用来对原始数据矩阵

进行近似:

原理示意图如图1所示:

这种思想和处理方式在图像压缩的应用中很有用处。

4.利用python进行实际操作

4.1.利用python进行奇异值分解

举一个

的矩阵

为例,

,这是一个看上去很有规律的矩阵。

我们这里就不按照推导SVD原理的过程:先求

,

,再接着获得

矩阵这样一步步计算。我们通过python提供的工具,直接一次性获得奇异值分解的所有结果。

代码片段:

import numpy as np

A=[[0, 0, 0, 2, 2],

[0, 0, 0, 3, 3],

[0, 0, 0, 1, 1],

[1, 1, 1, 0, 0],

[2, 2, 2, 0, 0],

[5, 5, 5, 0, 0],

[1, 1, 1, 0, 0]]

U, sigma, VT = np.linalg.svd(A)

print(U)

print(sigma)

print(VT)

运行结果:

[[ 0.00000000e+00 5.34522484e-01 8.41650989e-01 5.59998398e-02

-5.26625636e-02 1.14654380e-17 2.77555756e-17]

[ 0.00000000e+00 8.01783726e-01 -4.76944344e-01 -2.09235996e-01

2.93065263e-01 -8.21283146e-17 -2.77555756e-17]

[ 0.00000000e+00 2.67261242e-01 -2.52468946e-01 5.15708308e-01

-7.73870662e-01 1.88060304e-16 0.00000000e+00]

[ -1.79605302e-01 1.38777878e-17 7.39748546e-03 -3.03901436e-01

-2.04933639e-01 8.94308074e-01 -1.83156768e-01]

[ -3.59210604e-01 2.77555756e-17 1.47949709e-02 -6.07802873e-01

-4.09867278e-01 -4.47451355e-01 -3.64856984e-01]

[ -8.98026510e-01 5.55111512e-17 -8.87698255e-03 3.64681724e-01

2.45920367e-01 -6.85811202e-17 1.25520829e-18]

[ -1.79605302e-01 1.38777878e-17 7.39748546e-03 -3.03901436e-01

-2.04933639e-01 5.94635264e-04 9.12870736e-01]]

[ 9.64365076e+00 5.29150262e+00 7.40623935e-16 4.05103551e-16

2.21838243e-32]

[[ -5.77350269e-01 -5.77350269e-01 -5.77350269e-01 0.00000000e+00

0.00000000e+00]

[ -2.46566547e-16 1.23283273e-16 1.23283273e-16 7.07106781e-01

7.07106781e-01]

[ -7.83779232e-01 5.90050124e-01 1.93729108e-01 -2.77555756e-16

-2.22044605e-16]

[ -2.28816045e-01 -5.64364703e-01 7.93180748e-01 1.11022302e-16

-1.11022302e-16]

[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 -7.07106781e-01

7.07106781e-01]]

这样就非常简单的一次性获得了分解的结果,这里要强调一点,通过程序中获得的

变量不是一个矩阵,而是由

个奇异值按照从大到小顺序组成的列表,而最后一项,打印出来的不是

矩阵,而是转置后的矩阵

4.2.行和列的数据压缩实践

下面我们利用奇异值分解的结果进行行压缩和列压缩:

我们观察这一组奇异值,我们发现前两个奇异值在数量级上占有绝对的优势,因此我们选择

进行行压缩和列压缩。

依照上面介绍的知识点,我们利用

将矩阵

的行数由7行压缩成了2行。利用

,将矩阵

的行由5行压缩成了2行,换句话说就是将矩阵

的列由5列压缩成了2列。

代码片段:

import numpy as np

A=[[0, 0, 0, 2, 2],

[0, 0, 0, 3, 3],

[0, 0, 0, 1, 1],

[1, 1, 1, 0, 0],

[2, 2, 2, 0, 0],

[5, 5, 5, 0, 0],

[1, 1, 1, 0, 0]]

U, sigma, VT = np.linalg.svd(A)

U_T_2x7 = U.T[:2,:]

print(np.dot(U_T_2x7,A))

VT_2x5=VT[:2,:]

print(np.dot(VT_2x5,np.mat(A).T).T)

运行结果:

[[ -5.56776436e+00 -5.56776436e+00 -5.56776436e+00 0.00000000e+00

0.00000000e+00]

[ 3.60822483e-16 3.60822483e-16 3.60822483e-16 3.74165739e+00

3.74165739e+00]]

[[ 0.00000000e+00 2.82842712e+00]

[ 0.00000000e+00 4.24264069e+00]

[ 0.00000000e+00 1.41421356e+00]

[ -1.73205081e+00 -7.39557099e-32]

[ -3.46410162e+00 -1.47911420e-31]

[ -8.66025404e+00 -2.95822839e-31]

[ -1.73205081e+00 -7.39557099e-32]]

于是我们成功的分别将矩阵

的行和列进行了压缩。

4.3.利用数据压缩进行矩阵近似

最后,我们来实践一下如何对矩阵

的整体进行数据压缩。同样,我们取前两个奇异值

,利用

进行矩阵

的近似。

代码片段:

import numpy as np

A=[[0, 0, 0, 2, 2],

[0, 0, 0, 3, 3],

[0, 0, 0, 1, 1],

[1, 1, 1, 0, 0],

[2, 2, 2, 0, 0],

[5, 5, 5, 0, 0],

[1, 1, 1, 0, 0]]

U, sigma, VT = np.linalg.svd(A)

A_1 = sigma[0]*np.dot(np.mat(U[:, 0]).T, np.mat(VT[0, :]))

A_2 = sigma[1]*np.dot(np.mat(U[:, 1]).T, np.mat(VT[1, :]))

print(A_1+A_2)

运行结果:

[[ -6.97395509e-16 3.48697754e-16 3.48697754e-16 2.00000000e+00

2.00000000e+00]

[ -1.04609326e-15 5.23046632e-16 5.23046632e-16 3.00000000e+00

3.00000000e+00]

[ -3.48697754e-16 1.74348877e-16 1.74348877e-16 1.00000000e+00

1.00000000e+00]

[ 1.00000000e+00 1.00000000e+00 1.00000000e+00 5.19259273e-17

5.19259273e-17]

[ 2.00000000e+00 2.00000000e+00 2.00000000e+00 1.03851855e-16

1.03851855e-16]

[ 5.00000000e+00 5.00000000e+00 5.00000000e+00 2.07703709e-16

2.07703709e-16]

[ 1.00000000e+00 1.00000000e+00 1.00000000e+00 5.19259273e-17

5.19259273e-17]]

从运行结果来看,我们用较少的数据量实现了不错的矩阵近似效果。

此内容节选自我的专栏《机器学习中的数学:线性代数》,如有兴趣,欢迎订阅!机器学习中的数学:线性代数_专栏​gitbook.cn

-------------------------------------------------------------------------------------------

当然还有《机器学习中的数学》系列专栏,欢迎大家阅读,配合食用,效果更佳~机器学习中的数学:概率统计_专栏​gitbook.cn机器学习中的数学:微积分与最优化_专栏​gitbook.cn机器学习中的数学:概率图与随机过程_专栏​gitbook.cn

有订阅的问题可咨询微信:zhangyumeng0422

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值