SVD(Singular Value Decomposition)可以理解为:将一个比较复杂的矩阵用更小更简单的3个子矩阵的相乘来表示,这3个小矩阵描述了大矩阵重要的特性。
定义:矩阵的奇异值分解是指将一个秩为 r r r的实矩阵 A m × n A_{m \times n} Am×n分解为三个实矩阵乘积的形式:
A m × n = U m × m Σ m × n V n × n T ≈ U m × k Σ k × k V k × n T A_{m\times n} = U_{m \times m} \Sigma_{m \times n} V ^ { T }_{n\times n} \approx U_{m \times k} \Sigma_{k \times k} V ^ { T }_{k\times n} Am×n=Um×mΣm×nVn×nT≈Um×kΣk×kVk×nT
其中 U U U是 m m m阶正交矩阵( U U U的列向量称为左奇异向量), V V V是 n n n阶正交矩阵( V V V的列向量称为右奇异向量), Σ \Sigma Σ是 m × n m \times n m×n矩形对角矩阵,称为奇异值矩阵,对角线上的元素称为奇异值。
Σ = [ D r × r 0 0 0 ] m × n \Sigma = \begin{bmatrix} D_{r\times r}&0\\ 0&0\\ \end{bmatrix}_{m\times n} Σ=[Dr×r000]m×n
D D D是一个 r × r r \times r r×r的对角阵, D D D的对角线元素是 A A A的前 r r r个奇异值 σ 1 ≥ σ 2 ≥ ⋯ ≥ σ r > 0 \sigma _ { 1 } \geq \sigma _ { 2 } \geq \cdots \geq \sigma _ { r } > 0 σ1≥σ2≥⋯≥σr>0(非负,降序)。
知识点:任意一个实矩阵 A A A可以由其外积展开式表示
A = σ 1 u 1 v 1 T + σ 2 u 2 v 2 T + ⋯ + σ r u r v r T A = \sigma _ { 1 } u _ { 1 } v _ { 1 } ^ { T } + \sigma _ { 2 } u _ { 2 } v _ { 2 } ^ { T } + \cdots + \sigma _ { r } u _ { r } v _ { r } ^ { T } A=σ1u1v1T+σ2u2v2T+⋯+σrurvrT
其中 u k v k T u _ { k } v _ { k } ^ { T } ukvkT为 m × n m \times n m×n矩阵,是列向量 u k u _ { k } uk和行向量 v k T v _ { k } ^ { T } vkT的外积, σ k \sigma _ { k } σk为奇异值, u k , v k T , σ k u _ { k } , v _ { k } ^ { T } , \sigma _ { k } uk,vkT,σk通过矩阵 A A A的奇异值分解得到。
知识点:奇异值在矩阵中按照从大到小排列,在很多情况下,前10%甚至1%的奇异值的和就占了全部的奇异值之和的99%以上的比例。我们可以用最大的 k k k个奇异值的矩阵和 U V T UV^T UVT相乘来近似描述矩阵,从而实现了降维、减少数据存储、提升计算性能等效果。
设矩阵 A A A的奇异值分解为 A = U Σ V T A = U \Sigma V ^ { T } A=UΣVT,则有
A T A = V ( Σ T Σ ) V T A A T = U ( Σ Σ T ) U T \begin{array} { l } { A ^ { T } A = V ( \Sigma ^ { T } \Sigma ) V ^ { T } } \\ { A A ^ { T } = U ( \Sigma \Sigma ^ { T } ) U ^ { T } } \end{array} ATA=V(ΣTΣ)VTAAT=U(ΣΣT)UT
即对称矩阵 A T A A^TA ATA和 A A T AA^T AAT的特征分解可以由矩阵 A A A的奇异值分解矩阵表示。
证明: A T A A^TA ATA的特征值非负。
令 A A A是 m × n m \times n m×n矩阵,那么 A T A A^TA ATA是对称矩阵且可以正交对角化,让 { v 1 , … , v n } \{v_1,\dots,v_n\} {v1,…,vn}是 R n R^n Rn的单位正交基且构成 A T A A^TA ATA的特征向量, λ 1 , … , λ n \lambda_1,\dots,\lambda_n λ1,…,λn是 A T A A^TA ATA对应的特征值,那么对 1 ≤ i ≤ n 1\le{i}\le{n} 1≤i≤n,
∥ A v i ∥ 2 = ( A v i ) T ( A v i ) = v i T A T A v i = v i T λ i v i = λ i \| Av_i \|^2 = (Av_i)^T(Av_i)=v_i^TA^TAv_i =v_i^T\lambda_iv_i=\lambda_i ∥Avi∥2=(Avi)T(Avi)=viTATAvi=viTλivi=λi
所以 A T A A^TA ATA的所有特征值都非负,如果必要,通过重新编号我们可以假设特征值的重新排列满足
λ 1 ≥ λ 2 ≥ ⋯ ≥ λ n ≥ 0 \lambda_ { 1 } \geq \lambda_ { 2 } \geq \cdots \geq \lambda_ { n } \geq 0 λ1≥λ2≥⋯≥λn≥0
A A A的奇异值是 A T A A^TA ATA的特征值的平方根,记为 σ 1 , σ 2 , … , σ n \sigma_1,\sigma_2,\dots,\sigma_n σ1,σ2,…,σn,且它们递减顺序排列。
σ j = ∥ A v j ∥ = λ j , j = 1 , 2 , ⋯ , n \sigma _ { j } = \|Av_j \| = \sqrt { \lambda _ { j } }, \quad j = 1,2 , \cdots , n σj=∥Avj∥=λj,j=1,2,⋯,n
可见,对 A A A进行奇异值分解需要求矩阵 A T A A^TA ATA的特征值及其对应的标准正交的特征向量来构成正交矩阵 V V V的列,特征值 λ j \lambda _ { j } λj的平方根得到奇异值$\sigma _ { i } 也 即 得 到 奇 异 值 矩 阵 也即得到奇异值矩阵 也即得到奇异值矩阵\Sigma$。
证明:假设 { v 1 , v 2 , … , v n } \{v_1,v_2,\dots,v_n\} {v1,v2,…,vn}是包含 A T A A^TA ATA特征向量的 R n R^n Rn上的标准正交基,重新整理使得对应 A T A A^TA ATA的特征值满足 λ 1 ≥ λ 2 ≥ ⋯ ≥ λ n \lambda_1 \ge \lambda_2 \ge \dots \ge \lambda_n λ1≥λ2≥⋯≥λn。若 A A A有 r r r个非零奇异值,则 { A v 1 , A v 2 , … , A v r } \{Av_1,Av_2,\dots,Av_r\} {Av1,Av2,…,Avr}是 C o l A ColA ColA的一个正交基,且 r a n k A = r rank A = r rankA=r。
当 i i i不等于 j j j时, v i T v j = 0 v_i^Tv_j=0 viTvj=0。
( A v i ) T A v j = v i T A T A v j = λ j v i T v j = 0 (Av_i)^TAv_j = v_i^TA^TAv_j = \lambda_jv_i^Tv_j = 0 (Avi)TAvj=viTATAvj=λjviTvj=0
所以, { A v 1 , A v 2 , … , A v n } \{Av_1,Av_2,\dots,Av_n\} {Av1,Av2,…,Avn}是一个正交基。由于向量 A v 1 , A v 2 , … , A v n Av_1,Av_2,\dots,Av_n Av1,Av2,…,Avn的长度是 A A A的奇异值,且因为有 r r r个非零奇异值, A v i ( r ≥ i ≥ 1 ) Av_i (r\ge i\ge 1) Avi(r≥i≥1)为非零向量。所以 A v 1 , A v 2 , … , A v r Av_1,Av_2,\dots,Av_r Av1,Av2,…,Avr线性无关,且属于 C o l A ColA ColA。
对任意属于 C o l A ColA ColA的 y y y,如 y = A x y=Ax y=Ax,我们可以写出 x = c 1 v 1 + ⋯ + c n v n x=c_1v_1+\dots+c_nv_n x=c1v1+⋯+cnvn,且
y = A x = c 1 A v 1 + ⋯ + c r A r v r y = Ax = c_1Av_1+\dots+c_rA_rv_r y=Ax=c1Av1+⋯+crArvr
这样, y y y在 S p a n { A v 1 , … , A v r } Span\{Av_1,\dots,Av_r\} Span{Av1,…,Avr}中,这说明 { A v 1 , A v 2 , … , A v r } \{Av_1,Av_2,\dots,Av_r\} {Av1,Av2,…,Avr}是 C o l A ColA ColA的一个正交基,因此 r a n k A = d i m ( C o l A ) = r rank A = dim(ColA)=r rankA=dim(ColA)=r。
由于 { A v 1 , A v 2 , … , A v r } \{Av_1,Av_2,\dots,Av_r\} {Av1,Av2,…,Avr}是 C o l A ColA ColA的一个正交基,将每一个 A v i Av_i Avi单位化得到一个标准正交基 { u 1 , u 2 … u r } \{u_1,u_2\dots u_r\} {u1,u2…ur},此处
u i = 1 ∥ A v i ∥ A v i = 1 σ i A v i ( r ≥ i ≥ 1 ) u_i = \frac{1}{\|Av_i\|}Av_i = \frac{1}{\sigma_i}Av_i(r\ge i\ge1) ui=∥Avi∥1Avi=σi1Avi(r≥i≥1)
将 { u 1 , u 2 … u r } \{u_1,u_2\dots u_r\} {u1,u2…ur}扩充为 R m R^m Rm的单位正交基 { u 1 , u 2 … u m } \{u_1,u_2\dots u_m\} {u1,u2…um}。
取
U = ( u 1 , u 2 , … , u m ) , V = ( v 1 , v 2 , … , v n ) U=(u_1,u_2,\dots,u_m),V=(v_1,v_2,\dots,v_n) U=(u1,u2,…,um),V=(v1,v2,…,vn)
由构造可知, U U U和 V V V是正交矩阵,
A V = ( A v 1 , … , A v r , 0 , … , 0 ) = ( σ 1 u 1 , … , σ r u r , 0 … , 0 ) = U Σ AV=(Av_1,\dots,Av_r,0,\dots,0)=(\sigma_1u_1,\dots,\sigma_ru_r,0\dots,0)=U\Sigma AV=(Av1,…,Avr,0,…,0)=(σ1u1,…,σrur,0…,0)=UΣ
即: A = U Σ V T A=U \Sigma V^T A=UΣVT,从而得到 U U U。
知识点:任意给定一个实矩阵,其奇异值分解一定存在,但并不唯一。
1. 手动实现
# 实现奇异值分解, 输入一个numpy矩阵,输出 U, sigma, V
import numpy as np
# 基于矩阵分解的结果,复原矩阵
def rebuildMatrix(U, sigma, V):
a = np.dot(U, sigma)
a = np.dot(a, np.transpose(V))
return a
# 基于特征值的大小,对特征值以及特征向量进行倒序排列。
def sortByEigenValue(Eigenvalues, EigenVectors):
index = np.argsort(-1 * Eigenvalues)
Eigenvalues = Eigenvalues[index]
EigenVectors = EigenVectors[:, index]
return Eigenvalues, EigenVectors
# 对一个矩阵进行奇异值分解
def SVD(matrixA, NumOfLeft=None):
# NumOfLeft是要保留的奇异值的个数,也就是中间那个方阵的宽度
# 首先求transpose(A)*A
matrixAT_matrixA = np.dot(np.transpose(matrixA), matrixA)
# 然后求右奇异向量
lambda_V, X_V = np.linalg.eig(matrixAT_matrixA)
lambda_V, X_V = sortByEigenValue(lambda_V, X_V)
# 求奇异值
sigmas = lambda_V
# python里很小的数有时候是负数
sigmas = list(map(lambda x: np.sqrt(x) if x > 0 else 0, sigmas))
sigmas = np.array(sigmas)
sigmasMatrix = np.diag(sigmas)
if NumOfLeft is None:
# 大于0的特征值的个数
rankOfSigmasMatrix = len(list(filter(lambda x: x > 0, sigmas)))
else:
rankOfSigmasMatrix = NumOfLeft
# 特征值为0的奇异值就不要了
sigmasMatrix = sigmasMatrix[0:rankOfSigmasMatrix, :]
# 计算左奇异向量
# 初始化一个左奇异向量矩阵,这里直接进行裁剪
X_U = np.zeros((matrixA.shape[0], rankOfSigmasMatrix))
for i in range(rankOfSigmasMatrix):
X_U[:, i] = np.transpose(np.dot(matrixA, X_V[:, i]) / sigmas[i])
# 对右奇异向量和奇异值矩阵进行裁剪
X_V = X_V[:, 0:rankOfSigmasMatrix]
sigmasMatrix = sigmasMatrix[0:rankOfSigmasMatrix, 0:rankOfSigmasMatrix]
return X_U, sigmasMatrix, X_V
A = np.array([[4, 11, 14], [8, 7, -2]])
X_U, sigmasMatrix, X_V = SVD(A)
print(A)
# [[ 4 11 14]
# [ 8 7 -2]]
print(X_U.shape) # (2, 2)
print(sigmasMatrix.shape) # (2, 2)
print(X_V.shape) # (3, 2)
print(rebuildMatrix(X_U, sigmasMatrix, X_V))
# [[ 4. 11. 14.]
# [ 8. 7. -2.]]
2. 使用numpy.linalg.svd函数
import numpy as np
A = np.array([[4, 11, 14], [8, 7, -2]])
print(A)
# [[ 4 11 14]
# [ 8 7 -2]]
u, s, vh = np.linalg.svd(A, full_matrices=False)
print(u.shape) # (2, 2)
print(s.shape) # (2,)
print(vh.shape) # (2, 3)
a = np.dot(u, np.diag(s))
a = np.dot(a, vh)
print(a)
# [[ 4. 11. 14.]
# [ 8. 7. -2.]]
1. 数据压缩
奇异值分解可以有效地表示数据。例如,假设我们希望传输下面的图像,它由一个 25 × 15 25\times 15 25×15个黑色或白色像素组成的数组。
由于此图像中只有三种类型的列,如下图所示,因此可以用更紧凑的形式表示数据。
我们将图像表示为一个 25 × 15 25\times 15 25×15矩阵,矩阵的元素对应着图像的不同像素,如果像素是白色的话,就取 1,黑色的就取 0。 我们得到了一个具有375个元素的矩阵,如下图所示
如果对 M M M进行奇异值分解,我们会发现只有三个非零奇异值 σ 1 = 14.72 , σ 2 = 5.22 , σ 3 = 3.31 \sigma_1=14.72,\sigma_2=5.22,\sigma_3=3.31 σ1=14.72,σ2=5.22,σ3=3.31(非零奇异值的数目等于矩阵的秩,在这个例子中,我们看到矩阵中有三个线性无关的列,这意味着秩将是3)。
M = σ 1 u 1 v 1 T + σ 2 u 2 v 2 T + σ 3 u 3 v 3 T M = \sigma _ { 1 } u _ { 1 } v _ { 1 } ^ { T } + \sigma _ { 2 } u _ { 2 } v _ { 2 } ^ { T } + \sigma _ { 3 } u _ { 3 } v _ { 3 } ^ { T } M=σ1u1v1T+σ2u2v2T+σ3u3v3T
v i v_i vi具有15个元素, u i u_i ui 具有25个元素, σ i \sigma_i σi 对应不同的奇异值。我们就可以用123个元素来表示具有375个元素的图像数据了。通过这种方式,奇异值分解可以发现矩阵中的冗余,并提供消除冗余的格式。
2. 去噪
前面的例子展示了如何利用许多奇异值为零的情况。一般来说,大的奇异值对应的部分会包含更多的信息。假设我们使用扫描仪将此图像输入计算机。但是,我们的扫描仪会在图像中引入一些缺陷(通常称为“噪声”)。
我们可以用同样的方法进行:用一个 25 × 15 25\times 15 25×15矩阵表示数据,并执行奇异值分解。我们发现以下奇异值:
σ 1 = 14.15 , σ 2 = 4.67 , σ 3 = 3.00 , σ 4 = 0.21 , … , σ 15 = 0.05 \sigma_1=14.15,\sigma_2=4.67,\sigma_3=3.00,\sigma_4=0.21,\dots,\sigma_{15}=0.05 σ1=14.15,σ2=4.67,σ3=3.00,σ4=0.21,…,σ15=0.05
显然,前三个奇异值是最重要的,所以我们假设其它的都是由于图像中的噪声造成的,并进行近似。
M ≈ σ 1 u 1 v 1 T + σ 2 u 2 v 2 T + σ 3 u 3 v 3 T M \approx \sigma _ { 1 } u _ { 1 } v _ { 1 } ^ { T } + \sigma _ { 2 } u _ { 2 } v _ { 2 } ^ { T } + \sigma _ { 3 } u _ { 3 } v _ { 3 } ^ { T } M≈σ1u1v1T+σ2u2v2T+σ3u3v3T
这导致下面的改进图像。
3. 数据分析
我们搜集的数据中总是存在噪声:无论采用的设备多精密,方法有多好,总是会存在一些误差的。如果你们还记得上文提到的,大的奇异值对应了矩阵中的主要信息的话,运用SVD进行数据分析,提取其中的主要部分的话,还是相当合理的。
假设我们收集了一些数据,如下所示:
我们可以将数据放入矩阵中:
[ − 1.03 0.74 − 0.02 0.51 − 1.31 0.99 0.69 − 0.12 − 0.72 1.11 − 2.23 1.61 − 0.02 0.88 − 2.39 2.02 1.62 − 0.35 − 1.67 2.46 ] \begin{bmatrix} -1.03& 0.74 &-0.02 &0.51 &-1.31 &0.99 &0.69 &-0.12 &-0.72 &1.11\\ -2.23 &1.61 &-0.02 &0.88 &-2.39 &2.02 &1.62 &-0.35 &-1.67 &2.46\\ \end{bmatrix} [−1.03−2.230.741.61−0.02−0.020.510.88−1.31−2.390.992.020.691.62−0.12−0.35−0.72−1.671.112.46]
经过奇异值分解后,得到 σ 1 = 6.04 , σ 2 = 0.22 \sigma_1=6.04,\sigma_2 = 0.22 σ1=6.04,σ2=0.22。
由于第一个奇异值远比第二个要大,可以假设 σ 2 \sigma_2 σ2的小值是由于数据中的噪声产生的,并且该奇异值理想情况下应为零。在这种情况下,矩阵的秩为1,意味着所有数据都位于 u i u_i ui定义的行上。
参考文献