np.linalg.svd 给我错误的结果

问题描述 投票:0回答:1

所以我正在尝试学习 SVD 如何在 PCA(主成分分析)中使用它,但问题是它接缝我得到错误的结果,我尝试使用

np.linalg.svd
,这是我的代码:

A = np.array([[2, 2],
              [1, 1]])
u, s, v = np.linalg.svd(A, full_matrices=False)
print(u)
print(s)
print(v)

这是我得到的结果:

[[-0.89442719 -0.4472136 ]
 [-0.4472136   0.89442719]]
[3.16227766e+00 1.10062118e-17]
[[-0.70710678 -0.70710678]
 [ 0.70710678 -0.70710678]]

我尝试在 WolframAlpha 上进行 SVD 分解,我得到了这些结果:

值的大小似乎正确但符号不正确,甚至我在 MIT OpenCourseWare 上观看了一位教授的视频在 youtube 上,他给出了这些结果:

大小相同但符号不同的答案,那么可能出了什么问题?

python numpy linear-algebra svd wolframalpha
1个回答
3
投票

不同约定

返回矩阵的约定不同

v

来自

numpy.linalg.svd
(强调我的)的文档:

linalg.svd(a, full_matrices=True, compute_uv=True, hermitian=False)

奇异值分解。

当a是一个二维数组,并且full_matrices=False,那么它被分解为

u @ np.diag(s) @ vh = (u * s) @ vh
,其中
u
vh
的Hermitian转置是具有正交列的二维数组,s是a的一维数组奇异值。当
a
是高维时,SVD 以堆叠模式应用,如下所述。

Returns:

u{ (…, M, M), (…, M, K) }
array Unitary array(s).首先
a.ndim - 2
维度与输入
a
的大小相同。这 最后两个维度的大小取决于 full_matrices 的值。 仅在 compute_uv 为 True 时返回。

s(…, K)
array Vector(s) with the singular values, within each vector 按降序排列。第一个
a.ndim - 2
维度有 与输入的大小相同
a
.

vh
{ (…, N, N), (…, K, N) }
数组单一数组。第一个
a.ndim
- 2 个维度的大小与输入 a 的大小相同。的大小 最后两个维度取决于 full_matrices 的值。仅有的 当 compute_uv 为真时返回。

总结一下:给定

x
x = u @ np.diag(s) @ vh
的 SVD 分解,
numpy.linalg.svd(x)
返回的矩阵是
u
s
vh
,其中
vh
v
的厄密共轭。其他库和软件将返回
v
,导致明显的不一致。

遗憾的是,不同的图书馆有不同的约定,这也让我第一次不得不处理这个问题时感到很沮丧。

u
v

上的内在数学歧义

此外,问题的数学意味着矩阵

u
v
不是唯一确定的
.

为了检查 SVD 是否正确,您需要检查矩阵

u
v
确实是
x = u @ np.diag(s) @ vh
。如果两个条件都成立,则 SVD 是正确的,否则不是。

测试
numpy

这里是一些简单的代码,用于检查 SVD 库在 numpy 中的实现是否确实正确(当然是,认为这是一个教学练习):

import numpy as np

A = np.array([[2, 2],
              [1, 1]])
u, s, vh = np.linalg.svd(A, full_matrices=False)

smat = np.diag(s)

def is_unary(A):
    return np.allclose(A @ A.T, np.eye(A.shape[0]))

print(f"Is u unary? {is_unary(u)}")
print(f"Is vh unary? {is_unary(vh)}")
print(f"original matrix A")
print(A)
print("Reconstructed matrix A")
print(u @ smat @ vh)

def check_svd(A, u, s, vh):
    smat = np.diag(s)
    c1 = is_unary(u)
    c2 = is_unary(vh)
    c3 = np.allclose(A, u @ smat @ vh)
    success = c1 and c2 and c3
    if not success:
        raise Exception("numpy SVD failed")

for i in range(100):
    A = np.random.rand(100, 100)
    u, s, vh = np.linalg.svd(A, full_matrices=False)
    check_svd(A, u, s, vh)

print("All tests passed")
© www.soinside.com 2019 - 2024. All rights reserved.