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



我在Python中实现了一个非常简单的奇异值分解(不用担心,我知道numpy版本(,它更有趣。它基于A^TA和AA^T的特征向量的计算(例如,请参见此处(。理论上,这在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

在我看来,这应该会返回正确的矩阵。然而,这有一个问题:

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成立。

最新更新