• 奇异值分解(SVD)和np.linalg.svd()函数用法


    一、简介

            奇异值分解是一种十分重要但又难以理解的矩阵处理技术,在机器学习中是最重要的分解没有之一的存在。那么,奇异值分解到底是在干什么呢?

            矩阵 A 表示的是高维数据,通常情况下高维数据分布并不是雨露均沾的,而往往是厚此薄彼,集中分布在某些维度上,如下图

            虽然原始数据的的确确是二维数据,但是其实主要集中分布在直线 L (一维空间)附近,在这里,SVD(奇异值分解)其实就是在寻找直线 L ,然后将数据映射到直线 L 上,实现数据降维的过程,即如下图

            于是,通过SVD(奇异值分解),就可以利用降维后的数据近似地替代原始数据。所以,SVD(奇异值分解)其实就是在寻找数据分布的主要维度,将原始的高维数据映射到低维子空间中实现数据降维。

    二、概念

            奇异值分解(singular Value Decomposition),简称SVD,线性代数中矩阵分解的方法。假如有一个矩阵A,对它进行奇异值分解,可以得到三个矩阵:

    A ( m,n )= U ( m , m )\Sigma ( m , n ) V ( n , n )^T

            矩阵\Sigma除了对角元素不为0,其他元素都为0,并且对角元素是从大到小排列的,前面的元素比较大,后面的很多元素接近0。这些对角元素就是奇异值。

            \Sigma中有n个奇异值,但是由于排在后面的很多接近0,所以我们可以仅保留比较大的r个奇异值:

    A ( m,n )= U ( m , m )\Sigma ( r , r ) V ( r , n )^T

            实际应用中,我们仅需保留着三个比较小的矩阵,就能表示A,不仅节省存储量,在计算的时候更是减少了计算量。SVD在信息检索(隐性语义索引)、图像压缩、推荐系统、金融等领域都有应用。

            SVD一个重要的应用就是图像压缩存储,因为数字图像本身就是个矩阵,通过一个近似的低秩矩阵替代原矩阵,可以大大减少存储量。SVD还有很多用途,比如机器学习中的主成分分析,这才是直接利用低维矩阵 M 替代原矩阵 A 实现降维。

    三、np.linalg.svd(a,full_matrices=1,compute_uv=1)用法描述

    参数:
    a是一个形如(M,N)矩阵

    full_matrices的取值是为0或者1,默认值为1,这时u的大小为(M,M),v的大小为(N,N) 。否则u的大小为(M,K),v的大小为(K,N) ,K=min(M,N)。

    compute_uv的取值是为0或者1,默认值为1,表示计算u,s,v。为0的时候只计算s。

    返回值:

    总共有三个返回值u,s,v
    u大小为(M,M),s大小为(M,N),v大小为(N,N)。

    A = u*s*v

            其中s是对矩阵a的奇异值分解。s除了对角元素不为0,其他元素都为0,并且对角元素从大到小排列。s中有n个奇异值,一般排在后面的比较接近0,所以仅保留比较大的r个奇异值。 

    例子:

    1. >>> from numpy import *
    2. >>> data = mat([[1,2,3],[4,5,6]])
    3. >>> U,sigma,VT = np.linalg.svd(data)
    4. >>> print U
    5. [[-0.3863177  -0.92236578]
    6.  [-0.92236578  0.3863177 ]]
    7. >>> print sigma
    8. [9.508032   0.77286964]
    9. >>> print VT
    10. [[-0.42866713 -0.56630692 -0.7039467 ]
    11.  [ 0.80596391  0.11238241 -0.58119908]
    12.  [ 0.40824829 -0.81649658  0.40824829]]

            因为sigma是除了对角元素不为0,其他元素都为0。所以返回的时候,作为一维矩阵返回。本来sigma应该是由3个值的,但是因为最后一个值为0,所以直接省略了。 

    四、例子

    1. >>> a = np.random.randn(9, 6) + 1j*np.random.randn(9, 6)
    2. >>> b = np.random.randn(2, 7, 8, 3) + 1j*np.random.randn(2, 7, 8, 3)

    基于全 SVD 的重构,2D 案例:

    1. >>> u, s, vh = np.linalg.svd(a, full_matrices=True)
    2. >>> u.shape, s.shape, vh.shape
    3. ((9, 9), (6,), (6, 6))
    4. # numpy的allclose方法,比较两个array是不是每一元素都相等,默认在1e-05的误差范围内
    5. >>> np.allclose(a, np.dot(u[:, :6] * s, vh))
    6. True
    7. >>> smat = np.zeros((9, 6), dtype=complex)
    8. >>> smat[:6, :6] = np.diag(s)
    9. >>> np.allclose(a, np.dot(u, np.dot(smat, vh)))
    10. True

    基于简化 SVD 的重建,2D 案例:

    1. >>> u, s, vh = np.linalg.svd(a, full_matrices=False)
    2. >>> u.shape, s.shape, vh.shape
    3. ((9, 6), (6,), (6, 6))
    4. >>> np.allclose(a, np.dot(u * s, vh))
    5. True
    6. >>> smat = np.diag(s)
    7. >>> np.allclose(a, np.dot(u, np.dot(smat, vh)))
    8. True

    基于全SVD、4D案例的重构:

    1. >>> u, s, vh = np.linalg.svd(b, full_matrices=True)
    2. >>> u.shape, s.shape, vh.shape
    3. ((2, 7, 8, 8), (2, 7, 3), (2, 7, 3, 3))
    4. >>> np.allclose(b, np.matmul(u[..., :3] * s[..., None, :], vh))
    5. True
    6. >>> np.allclose(b, np.matmul(u[..., :3], s[..., None] * vh))
    7. True

    基于简化 SVD 的重建,4D 案例:

    1. >>> u, s, vh = np.linalg.svd(b, full_matrices=False)
    2. >>> u.shape, s.shape, vh.shape
    3. ((2, 7, 8, 3), (2, 7, 3), (2, 7, 3, 3))
    4. >>> np.allclose(b, np.matmul(u * s[..., None, :], vh))
    5. True
    6. >>> np.allclose(b, np.matmul(u, s[..., None] * vh))
    7. True

    参考文献:

    SVD(奇异值分解)到底在干什么 - 知乎

    这次终于彻底理解了奇异值分解(SVD)原理及应用

    数据科学中需要知道的5个关于奇异值分解(SVD)的应用

    奇异值分解的物理意义_SilenceHell的博客-CSDN博客_奇异值分解的意义

    奇异值分解的揭秘(一):矩阵的奇异值分解过程 - 知乎

  • 相关阅读:
    机器学习-逻辑回归算法
    Mybatis-Plus从入门到入土
    小红书达人怎么对接,博主沟通流程汇总!
    【ML特征工程】第 1 章 :机器学习管道
    网络安全(黑客技术)—2024自学手册
    记一次 .NET某机械臂上位系统 卡死分析
    编译使用Aws-cpp-sdk API
    Java编程中,使用时间戳机制实现增量更新的示例
    【Linux】vimrc 配置方案
    好库推荐|两个解决ja3检测的Python库,强烈推荐
  • 原文地址:https://blog.csdn.net/yangwohenmai1/article/details/127883752