为什么我的SVD计算与该矩阵的numpy的SVD计算不同?

时间:2018-09-24 19:53:18

标签: python numpy svd

我正在尝试手动计算下面定义的矩阵A的SVD,但是我遇到了一些问题。手动计算并使用numpy中的svd方法进行计算会产生两个不同的结果。

在下面手动计算:

import numpy as np
A = np.array([[3,2,2], [2,3,-2]])
V = np.linalg.eig(A.T @ A)[1]
U = np.linalg.eig(A @ A.T)[1]
S = np.c_[np.diag(np.sqrt(np.linalg.eig(A @ A.T)[0])), [0,0]]
print(A)
print(U @ S @ V.T)

并通过numpy的svd方法进行计算:

X,Y,Z = np.linalg.svd(A)
Y = np.c_[np.diag(Y), [0,0]]
print(A)
print(X @ Y @ Z)

运行这两个代码时。手动计算不等于svd方法。为什么这两种计算之间存在差异?

1 个答案:

答案 0 :(得分:1)

查看np.linalg.eig(A.T @ A)返回的特征值:

In [57]: evals, evecs = np.linalg.eig(A.T @ A)

In [58]: evals
Out[58]: array([2.50000000e+01, 3.61082692e-15, 9.00000000e+00])

因此(忽略正常的浮点不精确度),它计算出[25,0,9]。与这些特征值关联的特征向量以相同的顺序位于evecs的列中。但是您对S的构造与该顺序不匹配;这是您的S

In [60]: S
Out[60]: 
array([[5., 0., 0.],
       [0., 3., 0.]])

计算U @ S @ V.T时,S @ V.T中的值未正确对齐。

作为快速解决方案,您可以使用显式设置的S重新运行代码,如下所示:

S = np.array([[5, 0, 0],
              [0, 0, 3]])

更改后,您的代码将输出

[[ 3  2  2]
 [ 2  3 -2]]
[[-3. -2. -2.]
 [-2. -3.  2.]]

那更好,但是为什么迹象不正确?现在的问题是,您已经独立计算了UV。特征向量不是唯一的。它们是本征空间的基础,而这种基础并不是唯一的。如果特征值很简单,并且向量被标准化为长度为1(numpy.linalg.eig就是这样),那么仍然可以选择符号。也就是说,如果v是特征向量,那么-v也是特征向量。 eig在计算UV时所做的选择不一定会导致在计算A时恢复U @ S @ V.T的符号。

事实证明,您只需反转UV中的所有符号,即可获得预期的结果。这是脚本的修改后的版本,可生成您期望的输出:

import numpy as np

A = np.array([[3,  2,  2],
              [2,  3, -2]])

U = np.linalg.eig(A @ A.T)[1]
V = -np.linalg.eig(A.T @ A)[1]
#S = np.c_[np.diag(np.sqrt(np.linalg.eig(A @ A.T)[0])), [0,0]]
S = np.array([[5, 0, 0],
              [0, 0, 3]])

print(A)
print(U @ S @ V.T)

输出:

[[ 3  2  2]
 [ 2  3 -2]]
[[ 3.  2.  2.]
 [ 2.  3. -2.]]