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

26

我正在阅读 Abdi & Williams (2010) 的 "主成分分析",并尝试重新使用SVD来获得进一步PCA的值。

文章指出以下SVD:

X = P D Q^t

我将我的数据加载到 np.array X 中。

X = np.array(data)
P, D, Q = np.linalg.svd(X, full_matrices=False)
D = np.diag(D)

但是当我检查时,无法得到上述相等的结果。
X_a = np.dot(np.dot(P, D), Q.T)

X_a和X具有相同的维数,但值不相同。我是否遗漏了什么,或者是np.linalg.svd函数的功能与论文中的方程式不兼容?

4个回答

36

简而言之:numpy的SVD计算X=PDQ,因此Q已经被转置了。

SVD将矩阵X有效地分解为旋转矩阵P和Q以及对角线矩阵D。我使用的linalg.svd()版本返回P和Q的正向旋转。在计算Xa时,您不需要转换Q。

import numpy as np
X = np.random.normal(size=[20,18])
P, D, Q = np.linalg.svd(X, full_matrices=False)
X_a = np.matmul(np.matmul(P, np.diag(D)), Q)
print(np.std(X), np.std(X_a), np.std(X - X_a))

我得到了:1.02、1.02和1.8e-15,这表明X_a非常准确地重建了X

如果你在使用Python 3,@ 运算符可以实现矩阵乘法,并使代码更易于理解:

import numpy as np
X = np.random.normal(size=[20,18])
P, D, Q = np.linalg.svd(X, full_matrices=False)
X_a = P @ diag(D) @ Q
print(np.std(X), np.std(X_a), np.std(X - X_a))
print('Is X close to X_a?', np.isclose(X, X_a).all())

1
根据np.dot的文档,矩阵乘法应优先使用np.matmul - Rodrigo Laguna
2
根据Rodrigo的评论更新了答案。还添加了新的“@”符号。 - Frank M

8

我认为对于使用Python / linalg库中的SVD的人来说,仍然有一些重要的要点。首先,https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.svd.html 是SVD计算函数的良好参考。

将SVD计算视为A = U D (V ^ T),对于U,D,V = np.linalg.svd(A),此函数已经以V ^ T形式返回了V。另外,D仅包含特征值,因此必须将其转换为矩阵形式。因此,可以使用以下方式进行重构:

import numpy as np
U, D, V = np.linalg.svd(A)
A_reconstructed = U @ np.diag(D) @ V

重点是,如果一个矩阵A不是方形的而是矩形矩阵,这种方法将不起作用,您可以使用以下方法。
import numpy as np
U, D, V = np.linalg.svd(A)
m, n = A.shape
A_reconstructed = U[:,:n] @ np.diag(D) @ V[:m,:]

或者,您可以在SVD函数中使用“full_matrices=False”选项;

import numpy as np
U, D, V = np.linalg.svd(A,full_matrices=False)
A_reconstructed = U @ np.diag(D) @ V

5

以下内容摘自scipy.linalg.svd文档,其中(M,N)是输入矩阵的形状,K是两者中较小值:

Returns
-------
U : ndarray
    Unitary matrix having left singular vectors as columns.
    Of shape ``(M,M)`` or ``(M,K)``, depending on `full_matrices`.
s : ndarray
    The singular values, sorted in non-increasing order.
    Of shape (K,), with ``K = min(M, N)``.
Vh : ndarray
    Unitary matrix having right singular vectors as rows.
    Of shape ``(N,N)`` or ``(K,N)`` depending on `full_matrices`.

Vh,如描述所述,是在Abdi和Williams论文中使用的Q的转置。因此,只需

X_a = P.dot(D).dot(Q)

应该能够给您答案。

1

虽然这篇文章已经有一段时间了,但我认为它值得重要更新。在上面的答案中,正确的右奇异向量(通常放置在矩阵V的列中)被说成是直接从np.linalg.svd()的列中给出的。然而,这是不正确的。从np.linalg.svd()返回的矩阵是Vh,即V的共轭转置或厄米共轭,因此右奇异向量实际上在Vh的行中。要注意这一点,因为矩阵本身是方形的,所以您无法使用形状正确地确定这一点,但您可以使用重构来测试您是否正确地查看了矩阵。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接