有效地积累稀疏的scipy矩阵的集合

tim*_*day 7 python optimization numpy scipy sparse-matrix

我有一个O(N)NxN的集合scipy.sparse.csr_matrix,每个稀疏矩阵都有N个元素集的顺序.我想将所有这些矩阵一起添加到一个常规的NxN numpy数组中.(N大约为1000).矩阵内的非零元素的排列使得得到的和肯定不稀疏(事实上实际上没有留下零元素).

目前我正在做

reduce(lambda x,y: x+y,[m.toarray() for m in my_sparse_matrices])
Run Code Online (Sandbox Code Playgroud)

哪个有效但有点慢:当然,在那里进行的零点无意义处理绝对是可怕的.

有没有更好的办法 ?在文档中我没有什么明显的东西.

更新:根据user545424的建议,我尝试了对稀疏矩阵求和的替代方案,并将稀疏矩阵求和到密集矩阵上.下面的代码显示了在可比时间内运行的所有方法(在四核i7上的amd64 Debian/Squeeze上的Python 2.6.6)

import numpy as np
import numpy.random
import scipy
import scipy.sparse
import time

N=768
S=768
D=3

def mkrandomsparse():
    m=np.zeros((S,S),dtype=np.float32)
    r=np.random.random_integers(0,S-1,D*S)
    c=np.random.random_integers(0,S-1,D*S)
    for e in zip(r,c):
        m[e[0],e[1]]=1.0
    return scipy.sparse.csr_matrix(m)

M=[mkrandomsparse() for i in xrange(N)]

def plus_dense():
    return reduce(lambda x,y: x+y,[m.toarray() for m in M])

def plus_sparse():
    return reduce(lambda x,y: x+y,M).toarray()

def sum_dense():
    return sum([m.toarray() for m in M])

def sum_sparse():
    return sum(M[1:],M[0]).toarray()

def sum_combo():  # Sum the sparse matrices 'onto' a dense matrix?
    return sum(M,np.zeros((S,S),dtype=np.float32))

def benchmark(fn):
    t0=time.time()
    fn()
    t1=time.time()
    print "{0:16}:  {1:.3f}s".format(fn.__name__,t1-t0)

for i in xrange(4):
    benchmark(plus_dense)
    benchmark(plus_sparse)
    benchmark(sum_dense)
    benchmark(sum_sparse)
    benchmark(sum_combo)
    print
Run Code Online (Sandbox Code Playgroud)

并注销

plus_dense      :  1.368s
plus_sparse     :  1.405s
sum_dense       :  1.368s
sum_sparse      :  1.406s
sum_combo       :  1.039s
Run Code Online (Sandbox Code Playgroud)

虽然通过弄乱N,S,D参数可以得到一种方法或者另一种方法提前2倍左右...但是没有什么比你考虑数量时希望看到的数量级改进了零添加应该可以跳过.

use*_*424 4

如果你的矩阵非常稀疏,我想我已经找到了一种将其速度提高约 10 倍的方法。

In [1]: from scipy.sparse import csr_matrix

In [2]: def sum_sparse(m):
   ...:     x = np.zeros(m[0].shape)
   ...:     for a in m:
   ...:         ri = np.repeat(np.arange(a.shape[0]),np.diff(a.indptr))
   ...:         x[ri,a.indices] += a.data
   ...:     return x
   ...: 

In [6]: m = [np.zeros((100,100)) for i in range(1000)]

In [7]: for x in m:
   ...:     x.ravel()[np.random.randint(0,x.size,10)] = 1.0
   ...:     

        m = [csr_matrix(x) for x in m]

In [17]: (sum(m[1:],m[0]).todense() == sum_sparse(m)).all()
Out[17]: True

In [18]: %timeit sum(m[1:],m[0]).todense()
10 loops, best of 3: 145 ms per loop

In [19]: %timeit sum_sparse(m)
100 loops, best of 3: 18.5 ms per loop
Run Code Online (Sandbox Code Playgroud)

  • 惊人的。我刚刚在其他一些有稀疏-密集交互的地方应用了相同的模式 - 通常是点积类型的东西 - 并且每次都获得显着的加速(x2-x3)。 (2认同)