python - Numpy svd 与 Scipy.sparse svds

标签 python numpy scipy sparse-matrix svd

我正在致力于在 Python 中实现稀疏未定系统的求解器(已讨论 here ),并且我正在尝试重建使用标准 numpy svd 函数的零空间函数(numpy.linalg.svd) 在 SciPy cookbook 中使用 svd 的 scipy.sparse 版本(scipy.sparse.linalg.svds),但它为我运行的示例输出不同的左右奇异向量 - 包括矩阵:

[[1,1,0,0,0],[0,0,1,1,0],[1,1,1,1,1]]  
[[1,0,1],[1,1,0],[0,1,1]]

为什么这两个求解器会为上面的矩阵产生两个不同的 svd 输出?我该怎么做才能确保相同的输出?

编辑

这是一个示例:table 是一个 csc_matrix,使得

table.todense()  = matrix([[1,1,0,0,0],[0,0,1,1,0],[1,1,1,1,1]],dtype=int64)

因此,以下代码输出

numpy.linalg.svd(table.todense()) =  
[[ -3.64512933e-01   7.07106781e-01  -6.05912800e-01]  
[ -3.64512933e-01  -7.07106781e-01  -6.05912800e-01]  
[ -8.56890100e-01   2.32635116e-16   5.15499134e-01]]  
-----------------------------------------------------
[ 2.58873755  1.41421356  0.54629468]
-----------------------------------------------------
[[ -4.7181e-01 -4.7181e-01 -4.7181e-01 -4.7181e-01 -3.3101e-01]
[5e-01   5e-01  -5e-01  -5e-01 6.16450329e-17]
[-1.655e-01  -1.655e-01  -1.655e-01  -1.655e-01  9.436e-01]
[5e-01  -5e-01  -5e-01   5e-01 -1.77302319e-16]
[-5e-01  5e-01  -5e-01   5e-01 2.22044605e-16]]

以及以下

scipy.sparse.linalg.svds(table,k=2)=  
[[  7.07106781e-01,  -3.64512933e-01],
[ -7.07106781e-01,  -3.64512933e-01],
[  2.73756255e-18,  -8.56890100e-01]]
-------------------------------------
[ 1.41421356,  2.58873755]
-------------------------------------
[[  5e-01,   5e-01,  -5e-01, -5e-01,   1.93574904e-18],
[ -4.71814e-01,  -4.71814e-01,  -4.71814e-01, -4.71814e-01,  -3.31006e-01]]

请注意,两个解决方案之间有相当多的值重叠。另外,scipy.sparse.linalg.svds函数不允许k大于或等于min(table.shape),这就是我选择k的原因=2。

最佳答案

您发布的问题中的输出对我来说看起来不错。在 numpy 调用中,您计算​​每个奇异值,在 scipy 代码中,您仅计算前 k 个奇异值,并且它们与 numpy 输出中的前 k 个匹配。

稀疏 top k svd 不会让你计算每个奇异值,因为如果你想这样做,那么你可以使用完整的 svd 函数。

下面我提供了代码供您自行检查。需要注意的是,虽然 numpy 和 scipy full svd 都可以很好地重新创建原始矩阵,但前 k svd 却不能。这是因为您正在丢弃数据。通常情况下,只要你们距离足够近就可以了,这样就可以了。问题是 SVD 如果与 top k 一起使用,可以用作原始矩阵的低秩近似,而不是替代。

为了清楚起见,我在这方面的经验来自于为原作者A Sparse Plus Low-Rank Exponential Language Model for Limited Resource Scenarios实现本文的Python并行版本。 .

import numpy as np                                                                                   
from scipy import linalg                                                                            
from scipy.sparse import linalg as slinalg                                                           

x = np.array([[1,1,0,0,0],[0,0,1,1,0],[1,1,1,1,1]],dtype=np.float64)                                 

npsvd = np.linalg.svd(x)                                                                             
spsvd = linalg.svd(x)                                                                                
sptop = slinalg.svds(x,k=2)                                                                          

print "np"                                                                                           
print "u: ", npsvd[0]                                                                                
print "s: ", npsvd[1]                                                                                
print "v: ", npsvd[2]                                                                                

print "\n=========================\n"                                                                

print "sp"                                                                                           
print "u: ", spsvd[0]                                                                                
print "s: ", spsvd[1]                                                                                
print "v: ", spsvd[2]                                                                                

print "\n=========================\n"                                                                

print "sp top k"                                                                                     
print "u: ", sptop[0]                                                                                
print "s: ", sptop[1]                                                                                
print "v: ", sptop[2]                                                                                

nptmp = np.zeros((npsvd[0].shape[1],npsvd[2].shape[0]))                                              
nptmp[np.diag_indices(np.min(nptmp.shape))] = npsvd[1]                                               
npreconstruct = np.dot(npsvd[0], np.dot(nptmp,npsvd[2]))                                             

print npreconstruct                                                                                  
print "np close? : ", np.allclose(npreconstruct, x)                                                  

sptmp = np.zeros((spsvd[0].shape[1],spsvd[2].shape[0]))                                              
sptmp[np.diag_indices(np.min(sptmp.shape))] = spsvd[1]                                               
spreconstruct = np.dot(spsvd[0], np.dot(sptmp,spsvd[2]))                                             

print spreconstruct                                                                                  
print "sp close? : ", np.allclose(spreconstruct, x)                                                  

sptoptmp = np.zeros((sptop[0].shape[1],sptop[2].shape[0]))                                           
sptoptmp[np.diag_indices(np.min(sptoptmp.shape))] = sptop[1]                                         
sptopreconstruct = np.dot(sptop[0], np.dot(sptoptmp,sptop[2]))                                       

print sptopreconstruct                                                                               
print "sp top close? : ", np.allclose(sptopreconstruct, x)

关于python - Numpy svd 与 Scipy.sparse svds,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50884533/

相关文章:

python - 在 Pandas 中设置多列索引

python - 在 python 中加速插值

java - RFID + Android --> 我从哪里开始?

C++ 运行时类型与 Python 模块不匹配?

python - 在 Python 中,如何在 TinyDB 数据库中搜索值中的子字符串?

python - 如何将 Python 字典转换为 Class 对象

python - 以 SQLite 和 HDF5 格式从 numpy、scipy 导出/导入

python - 根据另一个 numpy 数组中的值查找 numpy 数组的索引

python - 获取给定顶点坐标的多边形轮廓和多边形掩码的坐标

python - scipy odeint : sum of conservative ode equations does not remain zero -- is this normal?