为什么我的 SVD 计算与 numpy 对该矩阵的 SVD 计算不同?
Why is my SVD calculation different than numpy's SVD calculation of this matrix?
我正在尝试手动计算下面定义的矩阵 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 方法。为什么这两个计算之间存在差异?
查看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.]]
这样更好,但为什么标志不对?现在的问题是你已经独立计算了 U
和 V
。特征向量不是唯一的;它们是特征空间的基础,并且这样的基础不是唯一的。如果特征值很简单,并且向量被归一化为长度为 1(numpy.linalg.eig
就是这样),则仍然可以选择符号。也就是说,如果 v
是特征向量,那么 -v
也是。 eig
在计算 U
和 V
时所做的选择不一定会导致在计算 U @ S @ V.T
时恢复 A
的符号。
事实证明,只需将 U
或 V
中的所有符号反转即可获得预期的结果。这是您的脚本的修改版本,可生成您期望的输出:
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.]]
我正在尝试手动计算下面定义的矩阵 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 方法。为什么这两个计算之间存在差异?
查看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.]]
这样更好,但为什么标志不对?现在的问题是你已经独立计算了 U
和 V
。特征向量不是唯一的;它们是特征空间的基础,并且这样的基础不是唯一的。如果特征值很简单,并且向量被归一化为长度为 1(numpy.linalg.eig
就是这样),则仍然可以选择符号。也就是说,如果 v
是特征向量,那么 -v
也是。 eig
在计算 U
和 V
时所做的选择不一定会导致在计算 U @ S @ V.T
时恢复 A
的符号。
事实证明,只需将 U
或 V
中的所有符号反转即可获得预期的结果。这是您的脚本的修改版本,可生成您期望的输出:
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.]]