在scipy.sparse.csr_matrix的一个轴上求和将产生一个numpy.matrix对象。 鉴于我的稀疏矩阵确实很稀疏,所以我发现这种行为非常烦人。
这里是一个例子:
dense = [[ 0., 0., 0., 0., 0.],
[ 1., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 2., 0., 4., 0., 0.]]
from scipy.sparse import csr_matrix
sparse = csr_matrix(dense)
print(sparse.sum(1))
结果:
matrix([[ 0.],
[ 1.],
[ 0.],
[ 0.],
[ 6.]])
如何在不对矩阵进行隐式转换为密集格式的情况下,对列求和运算强制执行稀疏?
在此示例中,我仅使用了一个小的n
矩阵,但是我的矩阵更大且稀疏,因此通过密集表示会浪费大量空间。
答案 0 :(得分:2)
sparse
通过矩阵乘法执行求和:
In [136]: np.matrix(np.ones(M.shape[1]))@M
Out[136]: matrix([[3., 0., 4., 0., 0.]])
In [137]: M@np.matrix(np.ones((M.shape[1],1)))
Out[137]:
matrix([[0.],
[1.],
[0.],
[0.],
[6.]])
In [138]: timeit M@np.matrix(np.ones((M.shape[1],1)))
91.5 µs ± 268 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [139]: timeit M.sum(1)
96.6 µs ± 647 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
时间是相似的。两者都产生np.matrix
结果。
如果将其与2d数组相乘,我会得到一个数组结果,而且出乎意料的是更好的时间:
In [140]: timeit M@np.ones((M.shape[1],1))
24.4 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [141]: M@np.ones((M.shape[1],1))
Out[141]:
array([[0.],
[1.],
[0.],
[0.],
[6.]])
我可以将该数组放回稀疏矩阵中-但要花一些时间:
In [142]: csr_matrix(M@np.ones((M.shape[1],1)))
Out[142]:
<5x1 sparse matrix of type '<class 'numpy.float64'>'
with 2 stored elements in Compressed Sparse Row format>
In [143]: timeit csr_matrix(M@np.ones((M.shape[1],1)))
391 µs ± 17.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
或者我们可以先创建一个稀疏矩阵:
In [144]: M@csr_matrix(np.ones((M.shape[1],1)))
Out[144]:
<5x1 sparse matrix of type '<class 'numpy.float64'>'
with 2 stored elements in Compressed Sparse Row format>
In [145]: timeit M@csr_matrix(np.ones((M.shape[1],1)))
585 µs ± 5.28 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
即使从循环中删除提取器矩阵的创建也会导致速度降低:
In [146]: %%timeit m1 = csr_matrix(np.ones((M.shape[1],1)))
...: M@m1
227 µs ± 4.72 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
sum
这样(几乎)总是增加结果的密度。每行具有至少一个非零值的矩阵比具有许多纯零行的矩阵更常见。在现实生活中,时间可能会有所不同,但是尝试使用相同的内存可能并不会给您带来多少好处。
如果我更详细地研究稀疏矩阵乘法产生的csr
矩阵:
In [147]: res = M@csr_matrix(np.ones((M.shape[1],1)))
In [148]: res
Out[148]:
<5x1 sparse matrix of type '<class 'numpy.float64'>'
with 2 stored elements in Compressed Sparse Row format>
In [149]: res.indptr
Out[149]: array([0, 0, 1, 1, 1, 2], dtype=int32)
In [150]: res.indices
Out[150]: array([0, 0], dtype=int32)
indptr
数组每行(+1)都有一个值,因此此列矩阵的内存使用实际上高于密集的等效项。 res
格式的相同csc
会更紧凑,带有2个元素indptr
。
还可以直接使用indptr
矩阵的indices
,data
和csr
属性,从本质上在行上进行迭代并对其求和创建一个新的稀疏矩阵。在某些情况下,与sparse
方法相比,我们已经提高了速度。但是您必须了解数据存储,并要对整个过程保持精明。