Numpy svd 与 Scipy.sparse svds
Numpy svd vs Scipy.sparse svds
我正在为 Python 中的稀疏未定系统实施求解器(讨论 ) and I was trying to rebuild the nullspace function that uses the standard numpy svd function (numpy.linalg.svd
) in the SciPy cookbook 使用 scipy.sparse 版本的 svd (scipy.sparse.linalg.svds
) 但它输出不同示例 I 运行 的左右奇异向量 - 包括矩阵:
[[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 个匹配。
稀疏前 k svd 不会让您计算每个奇异值,因为如果您想这样做,那么您可以只使用完整的 svd 函数。
下面我提供了代码供您自行检查。需要注意的是,虽然 numpy 和 scipy full svd 都可以很好地重新创建原始矩阵,但前 k 个 svd 不能。这是因为您正在丢弃数据。通常这很好,因为您可以足够接近。问题是,如果与前 k 一起使用,SVD 可以用作原始矩阵的低秩近似,而不是替代。
为清楚起见,我在这方面的经验来自为原作者 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)
u,sigma,v = numpy.linalg.svd(A)
等于
u,sigma,v = scipy.sparse.linalg.svds(A,k=min(A.shape[0],A.shape[1]))
u = -u[:,::-1]
v = -v[::-1,:]
sigma = sigma[::-1]
我正在为 Python 中的稀疏未定系统实施求解器(讨论 numpy.linalg.svd
) in the SciPy cookbook 使用 scipy.sparse 版本的 svd (scipy.sparse.linalg.svds
) 但它输出不同示例 I 运行 的左右奇异向量 - 包括矩阵:
[[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 个匹配。
稀疏前 k svd 不会让您计算每个奇异值,因为如果您想这样做,那么您可以只使用完整的 svd 函数。
下面我提供了代码供您自行检查。需要注意的是,虽然 numpy 和 scipy full svd 都可以很好地重新创建原始矩阵,但前 k 个 svd 不能。这是因为您正在丢弃数据。通常这很好,因为您可以足够接近。问题是,如果与前 k 一起使用,SVD 可以用作原始矩阵的低秩近似,而不是替代。
为清楚起见,我在这方面的经验来自为原作者 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)
u,sigma,v = numpy.linalg.svd(A)
等于
u,sigma,v = scipy.sparse.linalg.svds(A,k=min(A.shape[0],A.shape[1]))
u = -u[:,::-1]
v = -v[::-1,:]
sigma = sigma[::-1]