python svd给出了错误的结果

w46czmvw  于 2023-04-10  发布在  Python
关注(0)|答案(1)|浏览(289)

所以我试图学习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 on youtube和他给予这些结果:

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

o7jaxewo

o7jaxewo1#

不同的约定

返回矩阵v的约定不同:
numpy.linalg.svd的文档(强调我的):

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

奇异值分解
当a是一个2D数组,并且full_matrices=False时,则它被分解为**u @ np.diag(s) @ vh = (u * s) @ vh**,其中uvh的Hermitian转置是具有正交列的2D数组,s是a的奇异值的1D数组。当a是高维时,SVD以堆栈模式应用,如下所述。

返回u{ (…, M, M), (…, M, K) } array酉数组。前a.ndim - 2维度的大小与输入a的大小相同。后两个维度的大小取决于full_matrices的值。仅当compute_uv为True时返回。

s(…, K) array每个向量中的奇异值按降序排序。前a.ndim - 2维度与输入a维度的大小相同。

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

总结一下:给定xx = u @ np.diag(s) @ vh的SVD分解,numpy.linalg.svd(x)返回的矩阵是usvh,其中vhv的厄米共轭。其他库和软件将返回v,导致明显的不一致。
很遗憾,不同的库有不同的约定,这也是我第一次处理这个问题时遇到的问题。

uv的内在数学模糊性

此外,数学的问题意味着the matrices u and v are not uniquely determined
为了检查SVD是否正确,您需要检查矩阵uv是否确实是unitary以及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")

相关问题