机器学习 _ 用 SVD 奇异值分解给数据降维

  本想把 PCA 和 SVD 写在一起,可上篇 PCA 还没写清楚就已经 4 页 word 了。再把 SVD 和特征工程的内容加上,实在是太长了,一下说太多也记不住,于是重开一篇。

 SVD 用到的原理和 PCA 非常相似,就不再此赘述了,如果对特征值、特征向量相关问题不清楚请参见前篇 《机器学习_用PCA主成分分析给数据降维》

1. 原理

  先回忆一下特征值分解:把向量 x 往特征向量方向上分解,然后每个方向上做伸缩,最后再把结果加起来即可。也可以理解为将向量 x 转到正交坐标系,在各个坐标轴的方向上缩放后,再转换回原来的坐标系。只有方阵才能做特征值分解,因此我们在 PCA 中不是直接对数据做分解,而是对参数的协方差矩阵做分解。

  我们知道,任何矩阵都可以分解为三个矩阵的乘积 A=U * Sigma * VT,也就是奇异值分解.其中 U 和 VT 均是酉阵 (正交阵在复数域的推广),而 Sigma 为增广对角阵。从直观上讲,U 和 VT 可视为旋转操作,Sigma 可视为缩放操作。因此奇异值分解的含义就是说,若将矩阵看做一个变换,那么任何这样的变换可以看做是两个旋转和一个缩放变换的复合,这点和特征值分解基本一样。它也可以通过对 Sigma 的调整实现降维,通过 U 和 VT 在高维和低维间转换。相比特征值分解,奇异值分解可处理的不只是协方差矩阵(方阵),还可以直接处理数据。

图片引自百度百科

  但 SVD 也有一些问题,比如数据多的时候,奇异值分解的计算量会很大,不像 PCA 做特征值分解时,矩阵的大小只和属性个数相关。

2. 例程

(1) 功能

对矩阵 A 做 SVD 分解;降维;原始数据转到低维度;降维后的数据恢复到原来维度,看数据损失。

(2) 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from numpy import linalg
import array
import numpy as np

A=np.mat([[1,2,3],[4,5,6]])
U,Sigma,VT=linalg.svd(A)
print("U",U)
print("Sigma",Sigma)
print("VT",VT)
Sigma[1]=0 # 降维
print("Sigma",Sigma)

S = np.zeros((2,3))
S[:2, :2] = np.diag(Sigma)
print("A conv:", np.dot(np.dot(A.T, U), S)) # 原始数据转到低维
print("A':", np.dot(np.dot(U, S), VT)) # 恢复原始维度

(3) 运行结果

1
2
3
4
5
6
7
8
9
10
11
12
('U', matrix([[-0.3863177 , -0.92236578],
[-0.92236578, 0.3863177 ]]))
('Sigma', array([ 9.508032 , 0.77286964]))
('VT', matrix([[-0.42866713, -0.56630692, -0.7039467 ],
[ 0.80596391, 0.11238241, -0.58119908],
[ 0.40824829, -0.81649658, 0.40824829]]))
('Sigma', array([ 9.508032, 0. ]))
('A conv:', matrix([[-38.7526545 , 0. , 0. ],
[-51.19565893, 0. , 0. ],
[-63.63866337, 0. , 0. ]]))
("A':", matrix([[ 1.57454629, 2.08011388, 2.58568148],
[ 3.75936076, 4.96644562, 6.17353048]]))

(4) 分析

 SVD 分解矩阵 A,A 是一个 2x3(mn,其中 m 是行数)的矩阵,把它分解成三个矩阵的乘积:A=U Sigma * VT,其中 U 的大小是 2x2(mm),VT 为 33(nn),Sigma 为 min(m,n),从矩阵乘法的角度上看,Sigma 的大小应该是 mn,由于它是对角阵,为了简化,这里只取了对角线上元素。

 Sigma 奇异值为(9.508032,0.77286964),两值差异很大,说明转换后特征主要集中在一个维度上,于是降维,Sigma 调整 为(9.508032,0)。将原始矩阵 A 转置后乘 U 和调整后的 Sigma,实现了对 A 的降维。最后,将调整后的 Sigma 与 U,VT 相乘,映射回原始维度,变为矩阵 A’,对比之下,A’与 A 的也差不太多。不过把两维降成一维还是挺夸张的,在此只为举例,大家领会精神吧。

  这里比较重的是:观察 Sigma,决定保留前几项?svd() 函数对求出的奇异值和奇异向量按大小做了排序,其中值明显大的前 N 项,说明有 N 个“综合参数”最重要,因此,可以将数据降成 N 维。可降维度的多少,主要还是看数据的相关性,相关性越大,越适合降维。

3. 具体应用

(1) 图片压缩

  把图片的像素放一个矩阵里,做 SVD 分解,只保留 Sigma 中值大的前 N 项。则存储时只需保存三个矩阵,假设原图大小 100x100,N 为 5,则原图要 10000 点存储,而拆分后 100x5+100x5+5=1005,图像大小变为原来的 1/10。

(2) 数据降维

  矩阵中记 20 人试吃这 5 种套餐的评价(5x20),先对整体数据做 SVD 分解,假设保留 Sigma 的前 3 项,把原矩阵转置并和 U,Sigma 相乘,矩阵就从 520 维变成了 35 维。再套用各种学习算法时,数据就大大缩减了(从高维到低维投影)。不过 20 个维度变为 3 个维度后,属性意义也不像之前那么直观了,我们可以使用 VT 矩阵把数据恢复到原来的维度。