降维与压缩——奇异值分解(SVD)

一、特征值分解(EVD)的局限性

在进行主成分分析(PCA)的时候我们用到了特征值分解(EVD)的方法,这个方法很重要和很高效,但是同时也存在局限性。

那就是特征值分解要求矩阵必须是 方阵 并且一定能够被 对角化

那么扩展到一般情况,对于任意形状的矩阵的情况怎么办呢?比如说图片、数据表格等等。

那么奇异值分解(SVD)就进入了我们的视野,它可以对任意形状的矩阵进行分解,适用范围更广。

二、特征值分解的几何意义

我们一开始是获得一组原始的M X N 的数据采样矩阵A,其中M代表特征的个数,N代表样本个数。

\large A矩阵通过与自身的转置矩阵\large A^T相乘,\large AA^T得到M阶的样本特征的协方差矩阵\large C

然后获取协方差矩阵\large C的一组标准正交特征向量\large (q_1,q_2,q_3,...,q_m)以及对应的特征值\large (\lambda_1, \lambda_2, \lambda_3,..., \lambda_m )

此时,我们对协方差矩阵\large C进行特征值分解,将矩阵分解为这样的形式:

\large C = [q_1,q_2,q_3,...q_m]\begin{bmatrix} \lambda _1 & & & &\\ & \lambda _2 & & &\\ & & \lambda _3 & &\\ & & & ... &\\ & & & & \lambda _m \end{bmatrix} \begin{bmatrix} q_1^T\\ q_2^T\\ q_3^T\\ ...\\ q_m^T\\ \end{bmatrix}

最终通过获取前面k个特征值对应的特征向量,依次构成数据压缩矩阵\large P的各行,通过矩阵相乘\large PA进行投影达到数据压缩的目的。

我们可以看到,想要完成特征值分解,最终还是要回到\large Cq_i = \lambda _iq_i这个式子上来。

三、入手奇异值分解——Av = σμ

如果不进协方差矩阵\large C的获取,直接对原始的数据采样矩阵\large A进行矩阵分解,进行降维操作,显然是不行的。

特征值分解有两个大前提,一是必须是方阵,二是必须能够满足对角化。

但是对于原始的m x n 矩阵\large A可能连基本方阵的要求都达不到,根本无法进行特征值分解。

对于一个任意形状的m x n形状矩阵,我们有以下普遍意义的性质:

① 假设m>n,就有r≤n

②在\large R^n空间中一定有一组正交向量\large v_1,v_2,v_3,...v_n,在\large R^m空间中一定有一组正交向量\large v_1,v_2,v_3,...v_m

使之满足\large A\upsilon _i = \sigma_i\mu_i

在此基础上可以将

\large A[v_1.v_2.v_3,...v_n] = [\sigma_1\mu_1,\sigma_2\mu_2.\sigma_3\mu_3,...,\sigma_n\mu_n]

进一步转换为以下形式:

 

 \large A[v_1.v_2.v_3,...v_n] = [\mu_1.\mu_2,\mu_3,...\mu_n]\begin{bmatrix} \sigma_1 & & & & \\ & \sigma_2 & & & \\ & & \sigma_3 & & \\ & & & ... & \\ & & & & \sigma_n \end{bmatrix}

在这个分解的式子下,我们发现基向量\LARGE u_{_{^{n+1}}},u_{_{^{n+2}}},u_{_{^{n+3}}},...,u_{_{^{m}}}没有包含在内。

将其添加到矩阵右侧,得到完整的m阶方阵

\large U = [u_1,u_2,u_3,...,u_n,u_{_{^{n+1}}},u_{_{^{n+2}}},u_{_{^{n+3}}},...,u_{_{^{m}}}]

接下来,在对角矩阵下方加上 m - n 个全零行,形成m x n 的矩阵

降维与压缩——奇异值分解(SVD)_第1张图片

由于右下方全是全零行,所以结果不变。

此时得到等式

\large AV = U\Sigma

由于矩阵\large V各列是标准正交向量,有\large V^-1 = V^T,那么有一个矩阵分解的最终式子:

\large A = U\Sigma V^T

矩阵\large U和矩阵\large V是标准正交向量构成的m阶和n阶方阵,\large \Sigma是一个m x n 的对角矩阵,但不是方阵

接下来方阵\large U和方阵\large V要怎么求呢?矩阵\large \Sigma的各个值应该是多少?

我们先获取\large A的转置矩阵\large A^T = (U\Sigma V^T)^T = V\Sigma U^T

由此,可以获取两个对称矩阵\large AA^T\large A^TA

\large AA^T = U\Sigma U^T

\large A^TA = V\Sigma ^2V^T

由对称矩阵的性质可知,

矩阵\large A^TA一定有n个标准正交特征向量\large [v_1,v_2,v_3,...,v_n]

矩阵\large AA^T一定有m个标准正交特征向量\large [u_1,u_2,u_3,...,u_m]。这里\large v_i\large u_i 一 一对应。通过对应,即可求出\large U\large V

对应的,矩阵\large \Sigma也很好求,只要求出\large AA^T或者\large A^TA的非零特征值,从大到小排列\large \lambda_1, \lambda_2, \lambda_3,..., \lambda _r

那么矩阵\large \Sigma中对角线上的特征值 \large \sigma 依次为 \large \sqrt{\lambda_1}, \sqrt{\lambda_2}, \sqrt{\lambda_3},...,\sqrt{\lambda_r}

对角线上 \large \sigma _r 之后的特征值元素均为0

那么隐藏零特征值,得到完整的奇异值分解(SVD)的结果:

\large A= [\mu_1.\mu_2,\mu_3,...\mu_m] \begin{bmatrix} \sigma_1 & & & & \\ & \sigma_2 & & & \\ & & \sigma_3 & & \\ & & & ... & \\ & & & & \sigma_r \end{bmatrix} \begin{bmatrix} v_1^T\\ v_2^T\\ v_3^T\\ ...\\ v_n^T \end{bmatrix}

以下是一个抽象的示意图:

四、利用奇异值分解进行数据降维

奇异值分解(SVD)还有一个亮点就是,它可以从行或者列两个不同的维度同时进行对数据的降维处理

一个采样数据的矩阵的行和列通常代表着不同的特征。因此这种特性可以带来不同的处理效果。

1.行压缩数据降维

若要对行数据进行压缩,我们从矩阵\large A的奇异值分解式子\large A = U\Sigma V^T入手。

将等式两边同时乘以左奇异矩阵的转置矩阵\large U^T,得到\large U^TA = U^TU\Sigma v^T = \Sigma V^T

左侧表达式\large U^TA表示把矩阵\large A的n个m维列向量并排放置

\large [u_1,u_2,u_3,...u_m]^TA = \begin{bmatrix} u_1^T\\ u_2^T\\ u_3^T\\ ...\\ u_m^T\\ \end{bmatrix}[colA_1,colA_2,colA_3,cloA_n]= \begin{bmatrix} u_1^TcolA_1& u_1^TcolA_2& u_1^TcolA_3 & ... & u_1^TcolA_n \\ u_2^TcolA_1& u_2^TcolA_2& u_2^TcolA_3& ...& u_2^TcolA_n& \\ u_3^TcolA_1& u_3^TcolA_2& u_3^TcolA_3& ...& u_3^TcolA_n& \\ ...& ...& ...& ...& ...& \\ u_m^TcolA_1& u_m^TcolA_2& u_m^TcolA_3& ...& u_m^TcolA_n& \end{bmatrix}

此时,可以把每一列看作一个样本,各行是样本的不同特征,各行之间彼此无关,

此时可以选择最大的k个奇异值对应的k个标准正交向量,形成行压缩矩阵

降维与压缩——奇异值分解(SVD)_第2张图片

通过式子

降维与压缩——奇异值分解(SVD)_第3张图片 实现了列向量从m维降低到k维,完成主成分提取。

2.列压缩数据降维

列压缩数据降维也是同理,

我们也是从矩阵\large A的奇异值分解式子\large A = U\Sigma V^T出发,在式子两边同时乘以右奇异矩阵\large V

得到等式\large AV = U\Sigma

我们对左边的式子进行转置处理,\large (AV)^T = V^TA^T

把矩阵\large A记作:降维与压缩——奇异值分解(SVD)_第4张图片,那么有:
\large V^TA^T =\begin{bmatrix} v_1^T\\ v_2^T\\ v_3^T\\ ...\\ v_n^T\\ \end{bmatrix}[rowA_1,rowA_2,rowA_3,...,rowA_m] = \begin{bmatrix} v_1^TrowA_1& v_1^TrowA_2& v_1^TrowA_3& ...& v_1^TrowA_m& \\ v_2^TrowA_1& v_2^TrowA_2& v_2^TrowA_3& ...& v_2^TrowA_m& \\ v_3^TrowA_1& v_3^TrowA_2& v_3^TrowA_3& ...& v_3^TrowA_m& \\ ...& ...& ...& ...& ...& \\ v_n^TrowA_1& v_n^TrowA_2& v_n^TrowA_3& & v_n^TrowA_m& \end{bmatrix}

在矩阵\large v_3^T\large V中,从小到大去前k个特征值所对应的标准正交特征向量,就构成了另一个压缩矩阵

降维与压缩——奇异值分解(SVD)_第5张图片

通过乘法运算\large V_{k \times n}^TA^T就能够实现将矩阵\large A^T的各列由n维压缩到k维。

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

如果是要从矩阵整体处理视角来进行数据压缩,思路可以类似级数。

将一个m x n 的原始数据矩阵\large A分解为若干个相同维度矩阵乘以各自权重后相加的形式。

同样的,我们从\large A = U\Sigma V^T入手,展开:

\large A= [\mu_1.\mu_2,\mu_3,...\mu_m] \begin{bmatrix} \sigma_1 & & & & \\ & \sigma_2 & & & \\ & & \sigma_3 & & \\ & & & ... & \\ & & & & \sigma_r \end{bmatrix} \begin{bmatrix} v_1^T\\ v_2^T\\ v_3^T\\ ...\\ v_n^T \end{bmatrix}

将矩阵相乘的式子展开得到:

\large A = \sigma _1u_1v_1^T + \sigma _2u_2v_2^T + \sigma _3u_3v_3^T + ... + \sigma _ru_rv_r^T

展开式中每一个\large u_iv_i^T都代表一个等维的 m x n 的矩阵

前面系数 \large \sigma _i 表示每个矩阵“重要程度”,因此可以按照主成分贡献率的最低要求选择前k个项进行叠加,得到近似式子:

\large A \approx \sigma _1u_1v_1^T + \sigma _2u_2v_2^T + \sigma _3u_3v_3^T + ... + \sigma _ku_kv_k^T

原理抽象示意图如图所示:

降维与压缩——奇异值分解(SVD)_第6张图片

五、利用python进行奇异值分解

1. 一次性获得奇异值分解所有结果

这里可以不按照推导奇异值分解的过程:先求对称矩阵\large AA^T\large A^TA,再依次求得要的矩阵\large U\large V\large \Sigma

我们直接通过Python提供的工具一次性获得所有结果。

假设有一个矩阵

\large A = \begin{bmatrix} 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& \end{bmatrix}

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,V_T = np.linalg.svd(A)
print(U)
print(sigma)
print(V_T)
[[ 8.33888363e-17 -5.34522484e-01 -8.19688300e-01 -1.42578545e-02
   1.17589781e-01 -1.68291600e-01  6.64076653e-03]
 [-5.27910020e-33 -8.01783726e-01  4.81453408e-01 -3.68497530e-03
  -3.51336168e-01 -4.34953513e-02  1.71632139e-03]
 [ 0.00000000e+00 -2.67261242e-01  1.95016375e-01  3.95706349e-02
   8.18828941e-01  4.67069254e-01 -1.84304972e-02]
 [-1.79605302e-01  4.55126095e-17  8.85078821e-02  8.82844675e-01
   1.60750385e-01 -3.92953497e-01  1.55058983e-02]
 [-3.59210604e-01  6.56005654e-17  1.77015764e-01 -4.17392305e-01
   3.21500770e-01 -6.18874662e-01 -4.23140914e-01]
 [-8.98026510e-01  1.48333183e-18 -1.06209459e-01  3.21272177e-02
  -1.92900462e-01  3.79211394e-01 -1.49636365e-02]
 [-1.79605302e-01  3.28002827e-17  8.85078821e-02 -2.08696153e-01
   1.60750385e-01 -2.65354150e-01  9.05594112e-01]]

[9.64365076e+00 5.29150262e+00 6.49628424e-16 1.43063514e-16
 2.79192092e-17]

[[-5.77350269e-01 -5.77350269e-01 -5.77350269e-01  0.00000000e+00
   0.00000000e+00]
 [-1.70408510e-16  8.52042552e-17  8.52042552e-17 -7.07106781e-01
  -7.07106781e-01]
 [-6.19518612e-01 -1.50835436e-01  7.70354049e-01  2.48999108e-16
   1.37976805e-16]
 [-0.00000000e+00  8.56793076e-17 -8.56793076e-17  7.07106781e-01
  -7.07106781e-01]
 [ 5.31848997e-01 -8.02443355e-01  2.70594358e-01  5.04241948e-17
  -6.05981077e-17]]

这样就获得了奇异值分解所有的结果

sigma不是一个矩阵,是5个奇异值从大到小排序的一个列表

2. 行和列奇异值分解数据压缩

通过上面奇异值分解的结果

我们观察到前两个奇异值在数量级上有优势,所以我们选择k=2来进行行压缩和列压缩。

利用\large U_{2 \times 7}^TA将矩阵\large A的行数由7行压缩到2行。

利用\large V_{2 \times 5}^TA^T将矩阵\large A的列数由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,V_T = np.linalg.svd(A)
U_T_2x7 = U.T[:2,:]
print(np.dot(U_T_2x7,A))
V_T_2x5 = V_T[:2,:]
print(np.dot(V_T_2x5,np.mat(A).T).T)
[[-5.56776436e+00 -5.56776436e+00 -5.56776436e+00  1.66777673e-16
   1.66777673e-16]
 [ 2.16930682e-16  2.16930682e-16  2.16930682e-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  1.23259516e-32]
 [-3.46410162e+00  2.46519033e-32]
 [-8.66025404e+00  4.93038066e-32]
 [-1.73205081e+00  1.23259516e-32]]

 

3. 整体压缩——矩阵近似

接下来从整体维度进行数据压缩,取前两个贡献率高的奇异值 \large \sigma_1 和 \large \sigma_2 ,

利用\large \sigma _1u_1v_1^T + \sigma _2u_2v_2^T进行矩阵近似

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,V_T = np.linalg.svd(A)
A_1 = sigma[0] * np.dot(np.mat(U[:, 0]).T, np.mat(V_T[0, :]))
A_2 = sigma[1] * np.dot(np.mat(U[:, 1]).T, np.mat(V_T[1, :]))
print(A_1+A_2)
[[ 1.76986622e-17 -7.05283417e-16 -7.05283417e-16  2.00000000e+00
   2.00000000e+00]
 [ 7.22982080e-16 -3.61491040e-16 -3.61491040e-16  3.00000000e+00
   3.00000000e+00]
 [ 2.40994027e-16 -1.20497013e-16 -1.20497013e-16  1.00000000e+00
   1.00000000e+00]
 [ 1.00000000e+00  1.00000000e+00  1.00000000e+00 -1.70292592e-16
  -1.70292592e-16]
 [ 2.00000000e+00  2.00000000e+00  2.00000000e+00 -2.45454840e-16
  -2.45454840e-16]
 [ 5.00000000e+00  5.00000000e+00  5.00000000e+00 -5.55011948e-18
  -5.55011948e-18]
 [ 1.00000000e+00  1.00000000e+00  1.00000000e+00 -1.22727420e-16
  -1.22727420e-16]]

从得到的矩阵结果来看,近似矩阵为

\large \begin{bmatrix} 1.76e-17& -7.05e-16& -7.05e-16& 2.00e+00& 2.00e+00&\\ 7.22e-16& -3.61e-16& -3.61e-16& 3.00e+00& 3.00e+00&\\ 2.40e-16& -1.20e-16& -1.20e-16& 1.00e+00& 1.00e+00&\\ 1.00e+00& 1.00e+00& 1.00e+00& -1.70e-16& -1.70e-16&\\ 2.00e+00& 2.00e+00& 2.00e+00& -2.45e-16& -2.45e-16& \\ 5.00e+00& 5.00e+00& 5.00e+00& -5.55e-18& -5.55e-18&\\ 1.00e+00& 1.00e+00& 1.00e+00& -1.22e-16& -1.22e-16& \end{bmatrix}

与原来的矩阵

\large A = \begin{bmatrix} 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& \end{bmatrix} 对比,发现基本一致。实现了矩阵近似的效果。

 

你可能感兴趣的:(机器学习,机器学习,人工智能,数据分析,线性代数,python)