奇异值分解(SVD)及其应用

奇异值分解(SVD)及其应用_第1张图片

奇异值分解的定义

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×nTUm×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} 1in

∥ 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 Avi2=(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λn0

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(ri1)为非零向量。所以 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,u2ur},此处

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=Avi1Avi=σi1Aviri1

{ u 1 , u 2 … u r } \{u_1,u_2\dots u_r\} {u1,u2ur}扩充为 R m R^m Rm的单位正交基 { u 1 , u 2 … u m } \{u_1,u_2\dots u_m\} {u1,u2um}

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个黑色或白色像素组成的数组。

奇异值分解(SVD)及其应用_第2张图片

由于此图像中只有三种类型的列,如下图所示,因此可以用更紧凑的形式表示数据。

奇异值分解(SVD)及其应用_第3张图片

我们将图像表示为一个 25 × 15 25\times 15 25×15矩阵,矩阵的元素对应着图像的不同像素,如果像素是白色的话,就取 1,黑色的就取 0。 我们得到了一个具有375个元素的矩阵,如下图所示

奇异值分解(SVD)及其应用_第4张图片

如果对 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. 去噪

前面的例子展示了如何利用许多奇异值为零的情况。一般来说,大的奇异值对应的部分会包含更多的信息。假设我们使用扫描仪将此图像输入计算机。但是,我们的扫描仪会在图像中引入一些缺陷(通常称为“噪声”)。

奇异值分解(SVD)及其应用_第5张图片

我们可以用同样的方法进行:用一个 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

这导致下面的改进图像。

奇异值分解(SVD)及其应用_第6张图片

3. 数据分析

我们搜集的数据中总是存在噪声:无论采用的设备多精密,方法有多好,总是会存在一些误差的。如果你们还记得上文提到的,大的奇异值对应了矩阵中的主要信息的话,运用SVD进行数据分析,提取其中的主要部分的话,还是相当合理的。

假设我们收集了一些数据,如下所示:

奇异值分解(SVD)及其应用_第7张图片

我们可以将数据放入矩阵中:

[ − 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.032.230.741.610.020.020.510.881.312.390.992.020.691.620.120.350.721.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定义的行上。

奇异值分解(SVD)及其应用_第8张图片


参考文献

  • https://zhuanlan.zhihu.com/p/54693391
  • http://www.ams.org/publicoutreach/feature-column/fcarc-svd

你可能感兴趣的:(机器学习,Python学习)