SVD奇异值分解

Singular Value Decomposition

矩阵分解,特征值

  • 矩阵的特征值分解的原理
  • 目的是什么
  • 如何去使用。

为什么要对矩阵进行分解:知乎-马同学

1.SVD矩阵分解

任意实矩阵\(A\in R^{m * n}\)都可以进行分解\[A=U \Sigma V^{T}\]
\(U\in R^{m*m}\)是满足 \(U^{T}U=I\)的m阶酉矩阵 unitary matrix
\(V\in R^{m*m},\ V^{T} V=I\)的n阶酉矩阵
\(\Sigma \in R^{m*n}\)是m x n矩阵,其中\(\Sigma _{ii}=\sigma _{i}\)
\(\sigma_{i}\)为非负数,满足\(\sigma_{1} \geq \sigma_{2}\geq ...\geq 0\)

知识点扩充:酉矩阵

n阶复方阵U的n个列向量是U空间的一个标准正交基。酉矩阵是正交矩阵往复数域的推广

一些性质

1.\(\sigma_{i}\)奇异值按降序排***保\(\Sigma\)的唯一性
2.矩阵\(A\)的秩就是非零奇异值的个数
3.矩阵\(A\)的奇异值就是矩阵\(A*A^{T}\)特征值的平方根

2.SVD的实现

利用numpy函数包中linalg来实现

# 先看一个具体的案例
import numpy as np 
U,Sigma,VT=np.linalg.svd([[1,1],[7,7]])
print("the U is:\n {}\n Sigma is:\n {}\n VT is:\n {}".format(U,Sigma,VT));

输出
the U is:
[[-0.14142136 -0.98994949]
[-0.98994949 0.14142136]]
Sigma is:
[1.00000000e+01 2.82797782e-16]
VT is:
[[-0.70710678 -0.70710678]
[ 0.70710678 -0.70710678]]

这里要注意的是在numpy中为了节省储存空间,特征值矩阵Sigma 只输出对角线的元素(输出一列)

from numpy import *
from numpy import linalg as la
# construct the datasets
def loadExData():
    return[[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]]
if __name__ == '__main__':
    data=loadExData()
    U,Sigma,VT=linalg.svd(data)
    print("Sigma is:\n {}".format(Sigma))

输出结果:
Sigma is:
[9.64365076e+00 5.29150262e+00 6.49628424e-16 1.43063514e-16 2.79192092e-17]

开始对矩阵进行约简

采用启发式的策略来保留奇异值的数目:

  • 保留矩阵中90%的能量信息-所有奇异值的平方和为总能量,奇异值平方和累加到90%就可以。
  • 在科学和工程中,我们一般设置在r个奇异值之后,其余的奇异值都为0(非常小)。表示在数据集中只有r个重要特征,其余的特征都是噪声或者冗余特征。r=2000或3000

\[A_{7 \times 5} \approx U_{7 \times 2} \Sigma_{2 \times 2} V_{2 \times 5}^{T}\]

def Sigma(data):
    U,Sigma,VT=linalg.svd(data)
    return U,Sigma,VT
def SigmaReduce(U,Sigma,VT):
    sigmaReduce=mat([[Sigma[0],0],[0,Sigma[1]]])
    similarMatrix=U[:,:2]*sigmaReduce*VT[:2,:]
    return similarMatrix
if __name__ == '__main__':
    data=loadExData()
    U,Sigma,VT=Sigma(data)
    similarMatrix=SigmaReduce(U,Sigma,VT)
    print("the similarMatrix is :\n {}".format(similarMatrix))

结果是:
the similarMatrix is :
[[ 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]]

与原始数据相比较,几乎没有什么差距
表示可以使用sigma来进行代替约简矩阵

3.SVD的实际应用

基于协同过滤的推荐引擎
协同过滤-collaborative filtering

相似度的计算

  • 欧式距离计算相似度
    \[L_{P}(x_{i},x_{j})=(\sum _{i=1}^{n} \mid x_{i}^{l}- x_{j}^{l} \mid ^{p})^{\frac{1}{p}}\]

p=2的时候表示为欧式距离
可以利用 \[simiarity=\frac{1}{1+L_{p}distance}\]
来保证相似度在(0,1)之间,数值越大表示相似度越高。

  • Pearson correlation

在 numpy计算包中,可以使用 corrcoef()函数来实现计算
corrcoef()的输出是(-1,1),可以使用函数 0.5+0.5*corrcoef() 来将输出相似度保证在(0,1)之间

  • 余弦相似度-cosine similarity

\[cos \theta= \frac{A \cdot B} { \mid \mid A \mid \mid \cdot \mid \mid B \mid \mid } \]
\(\mid \mid A \mid \mid ,\mid \mid B \mid \mid\) 表示向量的2范数
夹角为90度,则相似度为0,方向相同则相似度为1。
范数的计算方法可以使用 numpy.linalg.norm()来计算

推荐引擎评价指标:最小均方根误差 root mean squared error RSME

对数字识别的图像进行压缩
结果是使用两个特征值就可以实现矩阵的近似,实现图像的重构
大大减小了存储空间

# import packages
def printMat(inMat,thresh=0.8):
    for i in range(32):
        for k in range(32):
            if float(inMat[i,k])>thresh:
                print("{}".format(1))
            else:
                print("{}".format(0))
        print("\n")
def imgCompress(numSV=3,thresh=0.8):
    myl=[]
    for line in open('0_5.txt').readlines():
        newRow=[]
        for i in range (32):
            newRow.append(int(line[i]))
        myl.append(newRow)
    myMat=mat(myl)

    # firsr,print the original matrix
    print(" the original matrix") 
    printMat(myMat,thresh)
    U,Sigma,VT=la.svd(myMat)
    sigRecon=mat(zeros((numSV,numSV)))
    # 还是需要把简化的 sigma 变成矩阵的形式
    for k in range(numSV):
        sigRecon[k,k]=Sigma[k]

    # 计算推荐矩阵
    ReconMat=U[:,:numSV]*sigRecon*VT[:numSV,:]

    # print the recommend matrix 
    print("the recommend matrix ")
    printMat(ReconMat,thresh)

if __name__ == '__main__':
    imgCompress()
全部评论

相关推荐

10-24 11:10
山西大学 Java
若梦难了:哥们,面试挂是很正常的。我大中厂终面挂,加起来快10次了,继续努力吧。
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务