为什么我自己在 python 中简单实现的 svd 算法不起作用?

Why does my own simple Implemantion of the svd algorithm in python not work?

我在 Python 中实现了一个非常简单的奇异值分解(不用担心我知道 numpy 版本),它更有趣。它基于 A^TA 和 AA^T 的特征向量的计算(参见示例 here)。这在理论上很容易实现 Python:

   def calc_svd(A: np.array):
    ATA = A.T@A
    AAT = A@A.T
    #compute the eigenvectors and sort them in ascending size of the eigenvalues
    eigenvalues_ATA, eigenvectors_ATA = np.linalg.eig(ATA)
    ATA_sorted = np.flip(np.argsort(eigenvalues_ATA))
    eigenvectors_ATA = eigenvectors_ATA[:, ATA_sorted]

    eigenvalues_AAT, eigenvectors_AAT = np.linalg.eig(AAT)
    AAT_sorted = np.flip(np.argsort(eigenvalues_AAT))
    eigenvalues_AAT = eigenvalues_AAT[AAT_sorted]
    eigenvectors_AAT = eigenvectors_AAT[:, AAT_sorted]
    sing_values = np.sqrt(eigenvalues_AAT)

    return U, sing_values, V.T

据我所知,这应该是 return 正确的矩阵。但是这有一个问题:

test = np.array([[1.0, 1.0, 0.0], [1.0, 3.0, 1.0], [2.0, -1.0, 1.0]])
u_np, svd_np, v_np = np.linalg.svd(test2)
u_own, svd_own, v_own = calc_svd(test2)
print(u_np@np.diag(svd_np)@v_np)
print(u_own@np.diag(svd_own)@v_own)

产生以下输出:

[[ 1.00000000e+00  1.00000000e+00  5.76517542e-16]
 [ 1.00000000e+00  3.00000000e+00  1.00000000e+00]
 [ 2.00000000e+00 -1.00000000e+00  1.00000000e+00]]
[[-0.53412934 -0.91106401 -0.94056803]
 [-1.17456455 -3.03332485 -0.64756347]
 [-2.08209125  0.98432856 -0.83426215]]

问题似乎是我的实现中U和V的一些特征向量是numpy之一的负值:

print(u_np)
print(u_own)
#results in
[[-0.35881632  0.13270783 -0.92392612]
 [-0.9317945  -0.10910581  0.34620071]
 [-0.05486216  0.98513174  0.16280537]]
[[ 0.35881632  0.13270783 -0.92392612]
 [ 0.9317945  -0.10910581  0.34620071]
 [ 0.05486216  0.98513174  0.16280537]]
#and
print(v_np)
print(v_own)
#in
[[-0.39543728 -0.87521453 -0.27861961]
 [ 0.80500544 -0.47631006  0.35368767]
 [-0.44226191 -0.08442901  0.89290321]]
[[-0.39543728 -0.87521453 -0.27861961]
 [-0.80500544  0.47631006 -0.35368767]
 [-0.44226191 -0.08442901  0.89290321]]

我的问题是我不明白为什么这不起作用。从数学的角度来看,采用特征向量 v 还是 -v 应该没有区别,因为它们都是具有相同特征值的特征向量。那么也许有人可以告诉我推理中的错误。

非常感谢您:)

该方法本身是正确的,但是您遇到了问题,因为 U 和 V 的特征向量在乘以 -1 时不是唯一确定的。

身份很重要

A * v_i = σ_i * u_i

适用于列 v_i、u_i 和奇异值 u_i。