(三)SVD奇异值分解及python实现(待修改)

奇异值分解(Singular Value Decomposition)是线性代数中一种重要的矩阵分解,奇异值分解则是特征分解在任意矩阵上的推广。在信号处理、统计学等领域有重要应用。

一 原理

对于矩阵 A m × n A_{m \times n} Am×n A = U Σ V − 1 A=U \Sigma V^{-1} A=UΣV1
U m × m , V n × n U_{m \times m},V_{n \times n} Um×m,Vn×n是标准正交矩阵,列向量为单位长度,且相互正交, U U T = I m , V V T = I n UU^T=I_m,VV^T=I_n UUT=Im,VVT=In Σ m × n \Sigma_{m \times n} Σm×n对角矩阵,对角元素非负,且从大到小排列。 A T A A^TA ATA的特征向量为V的列。 A A T AA^T AAT的特征向量为U的列。 A T A 或 A A T A^TA或AA^T ATAAAT的特征值求平方根,构成 Σ \Sigma Σ.
A T A V = V Σ T U T U Σ V T V = V Σ T Σ A A T U = U Σ V T V Σ T U T V = U Σ Σ T A^TA V =V\Sigma^TU^TU\Sigma V^T V =V\Sigma ^T \Sigma \\ AA^T U = U\Sigma V^T V\Sigma^TU^T V =U\Sigma \Sigma ^T ATAV=VΣTUTUΣVTV=VΣTΣAATU=UΣVTVΣTUTV=UΣΣT
一个m × n的矩阵至多有 p = min(m,n)个不同的奇异值

二 算法

输入:样本数据 A m × n A_{m\times n} Am×n
输出:左奇异矩阵,奇异值矩阵,右奇异矩阵
1.特征分解 ( A A T ) u i = λ i u i (AA^T)u_i=\lambda_iu_i (AAT)ui=λiui,得到的特征矩阵为左奇异矩阵 U U U,特征值对角矩阵为 Σ Σ T \Sigma \Sigma^T ΣΣT Σ ′ = Σ Σ T \Sigma^{'}=\sqrt{\Sigma \Sigma^T} Σ=ΣΣT m × m m\times m m×m的矩阵, Σ r \Sigma_r Σr取前 r r r项。
2.由 A = U Σ ′ V T ′ A=U\Sigma^{'} V^{T'} A=UΣVT V T ′ = ( U Σ ′ ) − 1 A = ( Σ ′ ) − 1 U T A V^{T'}=(U\Sigma^{'})^{-1}A= (\Sigma^{'})^{-1}U^TA VT=(UΣ)1A=(Σ)1UTA ,求得 V T ′ V^{T'} VT
3.返回 U m × m , V n × m T ′ , Σ m × m ′ U_{m\times m},V^{T'}_{n\times m},\Sigma^{'}_{m\times m} Um×m,Vn×mT,Σm×m
3.重建数据 A = U m × r Σ r × r V n × r T A=U_{m\times r} \Sigma_{r\times r} V^T_{n\times r} A=Um×rΣr×rVn×rT

三 SVD和PCA对比

数据 A m × n A_{m\times n} Am×n,在PCA做降维数据 A m × n P n × r = A ~ m × r (1) A_{m\times n}P_{n\times r}=\tilde{A} _{m\times r} \tag{1} Am×nPn×r=A~m×r(1)奇异值分解 A m × n ≈ U m × r Σ r × r V n × r T A_{m\times n} \approx U_{m\times r} \Sigma_{r\times r} V^T_{n\times r} Am×nUm×rΣr×rVn×rT两边同时右乘以 V n × r V_{n\times r} Vn×r,得到 A m × n V n × r ≈ U m × r Σ r × r V n × r T V n × r A_{m\times n} V_{n\times r} \approx U_{m\times r} \Sigma_{r\times r} V^T_{n\times r} V_{n\times r} Am×nVn×rUm×rΣr×rVn×rTVn×r A m × n V n × r ≈ U m × r Σ r × r (2) A_{m\times n} V_{n\times r} \approx U_{m\times r} \Sigma_{r\times r} \tag{2} Am×nVn×rUm×rΣr×r(2) ( 1 ) ( 2 ) (1)(2) (1)(2)两个式子对比, P n × r P_{n\times r} Pn×r相当于 V n × r V_{n\times r} Vn×r,PCA得到新的数据 A ~ m × r \tilde{A} _{m\times r} A~m×r相当于 U m × r Σ r × r U_{m\times r} \Sigma_{r\times r} Um×rΣr×r。都是对矩阵的列进行了压缩(行压缩使用 U m × r T U_{m\times r}^T Um×rT左乘)。其实PCA几乎可以说是对SVD的一个包装,如果我们实现了SVD,那也就实现了PCA了,而且更好的地方是,有了SVD,我们就可以得到两个方向的PCA,如果我们对 A T A A^TA ATA进行特征值的分解,只能得到一个方向的PCA。

四 举例

奇异值可以被看作成一个矩阵的代表值,或者说,奇异值能够代表这个矩阵的信息。当奇异值越大时,它代表的信息越多。因此,我们取前面若干个最大的奇异值,就可以基本上还原出数据本身。
(1)使用np.linalg.svd

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
 

#读取图片
img_eg = mpimg.imread("2.jpg")
print(img_eg.shape)
#(650, 650, 3)

#奇异值分解
img_temp = img_eg.reshape(650, 650* 3)#先将图片变成600×1200,再做奇异值分解。
U,Sigma,VT = np.linalg.svd(img_temp)#从svd函数中得到的奇异值sigma它是从大到小排列的。

#取前部分奇异值重构图片
# 取前60个奇异值
sval_nums = 60
img_restruct1 = (U[:,0:sval_nums]).dot(np.diag(Sigma[0:sval_nums])).dot(VT[0:sval_nums,:])
img_restruct1 = img_restruct1.reshape((650, 650, 3))
 
# 取前120个奇异值
sval_nums = 120
img_restruct2 = (U[:,0:sval_nums]).dot(np.diag(Sigma[0:sval_nums])).dot(VT[0:sval_nums,:])
img_restruct2 = img_restruct2.reshape((650, 650, 3))

#将照片显示出来,对比效果
fig, ax = plt.subplots(1,3,figsize = (24,32))
 
ax[0].imshow(img_eg)
ax[0].set(title = "src")
ax[1].imshow(img_restruct1.astype(np.uint8))
ax[1].set(title = "nums of sigma = 60")
ax[2].imshow(img_restruct2.astype(np.uint8))
ax[2].set(title = "nums of sigma = 120")

(2)自己构造函数,奇异值矩阵和右奇异矩阵与上述方法不同,但不影响结果

import numpy as np
import pandas as pd
from scipy.io import loadmat
 
# 读取数据,使用自己数据集的路径。
train_data_mat = loadmat("train_data2.mat")
train_data = train_data_mat["Data"]
print(train_data.shape)

# 数据必需先转为浮点型,否则在计算的过程中会溢出,导致结果不准确
train_dataFloat = train_data / 255.0

def SVD(train_dataFloat):
    # 计算特征值和特征向量
    eval_sigma1,evec_u = np.linalg.eigh(train_dataFloat.dot(train_dataFloat.T))

    #降序排列后,逆序输出
    eval1_sort_idx = np.argsort(eval_sigma1)[::-1]
    # 将特征值对应的特征向量也对应排好序
    eval_sigma1 = np.sort(eval_sigma1)[::-1]
    evec_u = evec_u[:,eval1_sort_idx]

    # 计算奇异值矩阵的逆
    eval_sigma1 = np.diag(np.sqrt(eval_sigma1))
    eval_sigma1_inv = np.linalg.inv(eval_sigma1)
    # 计算右奇异矩阵
    evec_part_vT = eval_sigma1_inv.dot((evec_u.T).dot(train_dataFloat))
    evec_part_v=np.transpose(evec_part_vT)
    return evec_u,eval_sigma1,evec_part_vT

evec_u,eval_sigma1,evec_part_vT=SVD(train_dataFloat)
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值