代码之家  ›  专栏  ›  技术社区  ›  Rushabh Mehta

numpy svd与scipy.sparse svd

  •  1
  • Rushabh Mehta  · 技术社区  · 8 年前

    我正在用python实现一个稀疏不确定系统的解算器(讨论过 here )我试图重建使用标准numpy svd函数的nullspace函数( numpy.linalg.svd )在这条弯道上 cookbook 使用scipy.sparse版本的svd( 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输出?我能做些什么来确保相同的输出?

    编辑

    下面是一个例子: 桌子 是一个 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的原因。

    1 回复  |  直到 8 年前
        1
  •  3
  •   David    8 年前

    在我看来,你发布的问题的结果很好。在numpy调用中,计算每个奇异值,在scipy代码中,只计算前k个奇异值,它们与numpy输出中的前k个匹配。

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

    下面我已经包括了代码,让你自己检查一下。需要注意的是,尽管numpy和scipy全svd都可以很好地重建原始矩阵,但顶级k svd不能。这是因为你在丢弃数据。通常情况下,这是好的,因为你是足够接近。问题是,如果svd与top k一起使用,则可以用作原始矩阵的低阶近似,而不是替换。

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

    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)