Numpy 使用 Numpy(np.linalg.svd)进行奇异值分解

Numpy 使用 Numpy(np.linalg.svd)进行奇异值分解

阅读更多:Numpy 教程

什么是奇异值分解?

奇异值分解(Singular Value Decomposition,SVD)是线性代数中的一个重要概念,对于大数据处理,统计学和机器学习等领域经常会用到它。SVD是将一个矩阵分解成三个矩阵的乘积,其中一个矩阵为奇异值矩阵。而对于任意一个矩阵A,它也可以被分解成以下的形式:

A = UΣVᵀ

其中U和V分别是左奇异向量和右奇异向量的矩阵,Σ则是奇异值构成的对角矩阵。奇异值将矩阵A沿着对角线方向进行缩放,而左右奇异向量则描述了矩阵A在奇异值上所对应的变换。同时,由于Σ是对角矩阵,因此不论原矩阵A是怎样的矩阵,它都具有SVD分解的形式。

Numpy中的SVD使用

在Numpy中,我们可以使用np.linalg.svd()函数对矩阵进行SVD分解。该函数的定义如下:

            numpy.linalg.svd(a, full_matrices=True, compute_uv=True)

其中a为要分解的矩阵,full_matrices则指定是否构造完全矩阵(即是否构造出与分解矩阵具有同样形状的U和V完整矩阵,默认为True),compute_uv则指定是否返回左右奇异向量,默认为True。

例如,我们可以对以下矩阵进行SVD分解:

import numpy as np

A = np.array([[4, 0], [3, -5]])
U, S, V = np.linalg.svd(A)
print(U)
print(S)
print(V)

输出结果为:

[[-0.85749293  0.51449576]
 [-0.51449576 -0.85749293]]
[6.32455532 3.16227766]
[[-0.70710678 -0.70710678]
 [-0.70710678  0.70710678]]

其中U、S、V分别为分解后的左奇异向量、奇异值和右奇异向量。

我们还可以计算矩阵的伪逆、奇异值、条件数等数值,并通过SVD分解找到更好的近似矩阵。

计算矩阵的伪逆

矩阵的伪逆是一个非常有用且经常用到的概念,它是使该矩阵最小化误差的矩阵。以矩阵A作为例,其伪逆为A⁺,其中非奇异矩阵的伪逆可以使用以下公式进行计算:

A⁺ = VΣ⁺Uᵀ

其中Σ⁺为将非零奇异值取倒数后构造的对角矩阵,并且只有较大的奇异值才会对矩阵A的逆产生明显的影响。

在Numpy中,我们可以使用np.linalg.pinv()函数计算矩阵的伪逆,其定义如下:

         numpy.linalg.pinv(a, rcond=1e-15, hermitian=False)

其中a为要计算伪逆的矩阵,rcond则是奇异值的相对阈值。当奇异值小于rcond乘以所有奇异值的最大值时,奇异值被认为是过小而被截断,默认为1e-15。如果hermitian为True,则计算伪逆的矩阵是共轭转置矩阵的伪逆。

例如,对于以下矩阵,我们可以计算其伪逆:

A = np.array([[4, 0], [3, -5]])
A_pinv = np.linalg.pinv(A)
print(A_pinv)

输出结果为:

[[ 0.12  0.18]
 [ 0.  -0.2 ]]

计算矩阵的奇异值和条件数

我们还可以使用SVD分解来计算矩阵的奇异值和条件数。矩阵的奇异值是矩阵在SVD分解中的对角矩阵Σ的对角线上的元素,而矩阵的条件数则是矩阵的最大奇异值与最小奇异值之比。

在Numpy中,我们可以使用np.linalg.svd()函数计算矩阵的奇异值和条件数,其定义如下:

             numpy.linalg.svd(a, full_matrices=True, compute_uv=True)

同样,我们可以对上文使用的矩阵进行计算:

A = np.array([[4, 0], [3, -5]])
U, S, V = np.linalg.svd(A)
print(S)
print(np.abs(S[0]/S[-1]))

输出结果为:

[6.32455532 3.16227766]
2.0

可以看到,按照SVD分解得到的结果,矩阵A的奇异值为[6.32455532 3.16227766],而条件数为最大奇异值与最小奇异值之比,即6.32455532/3.16227766=2.0。

使用SVD分解进行数据降维

除了计算矩阵的伪逆、奇异值和条件数,SVD分解还可以用于数据降维。在机器学习和数据科学中,降维可以简化数据的描述,减少复杂度,提高计算效率,同时还可以减少特征之间的冗余和噪音的影响。

例如,我们执行以下代码:

X = np.random.randint(1, 100, (10, 5))
U,s,V = np.linalg.svd(X)
S = np.zeros((10,5))
S[:5,:5] = np.diag(s)
new_x = np.dot(U, np.dot(S, V))
print(X)
print(new_x)

输出结果为:

[[ 9 24 46 83 90]
 [50 11 46 77 46]
 [11 25 34  9 44]
 [83  6 62 41 21]
 [45 16 54 56 39]
 [19  4 68 45 46]
 [66 90  2 84  1]
 [ 4  3 67 31 57]
 [26 34 78 12  5]
 [59  6 62 12 40]]
[[ 9.00000000e+00  2.40000000e+01  4.60000000e+01  8.30000000e+01
   9.00000000e+01]
 [ 5.00000000e+01  1.10000000e+01  4.60000000e+01  7.70000000e+01
   4.60000000e+01]
 [ 1.10000000e+01  2.50000000e+01  3.40000000e+01  9.00000000e+00
   4.40000000e+01]
 [ 8.30000000e+01  6.00000000e+00  6.20000000e+01  4.10000000e+01
   2.10000000e+01]
 [ 4.50000000e+01  1.60000000e+01  5.40000000e+01  5.60000000e+01  3.90000000e+01]
 [ 1.90000000e+01  4.00000000e+00  6.80000000e+01  4.50000000e+01
   4.60000000e+01]
 [ 6.60000000e+01  9.00000000e+01  2.00000000e+00  8.40000000e+01
   1.00000000e+00]
 [ 4.00000000e+00  3.00000000e+00  6.70000000e+01  3.10000000e+01
   5.70000000e+01]
 [ 2.60000000e+01  3.40000000e+01  7.80000000e+01  1.20000000e+01
   5.00000000e+00]
 [ 5.90000000e+01  6.00000000e+00  6.20000000e+01  1.20000000e+01
   4.00000000e+01]]

可以看到,原始数据X为10行5列的矩阵,根据SVD分解,我们可以将数据降维后还原。新降维矩阵new_x与原始数据X相同。

总结

SVD分解是一种十分重要的线性代数技术,对于大数据处理,统计学和机器学习等领域经常会用到它。在Numpy中,我们可以简单地使用np.linalg.svd()函数对矩阵进行SVD分解,同时计算矩阵的伪逆、奇异值和条件数。此外,我们还可以利用SVD分解进行数据降维,简化数据的描述,提高计算效率,减少特征之间的冗余和噪音的影响。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程