我的代码中有以下表达式:

a = (b / x[:, np.newaxis]).sum(axis=1)

其中b是形状(M, N)的ndarray,而x是形状(M,)的ndarray。现在,b实际上是稀疏的,因此为了提高内存效率,我想用scipy.sparse.csc_matrixcsr_matrix代替。但是,未实现以这种方式进行广播(即使保证了除法或乘法可保持稀疏性)(x的条目不为零),并引发了NotImplementedError。有我不知道的sparse函数可以实现我想要的功能吗? (dot()将沿错误的轴求和。)

最佳答案

如果b为CSC格式,则b.data具有b的非零条目,而b.indices具有每个非零条目的行索引,因此您可以按以下方式进行除法:

b.data /= np.take(x, b.indices)

它比沃伦(Warren)的优雅解决方案更加骇人听闻,但在大多数情况下,它可能也会更快:
b = sps.rand(1000, 1000, density=0.01, format='csc')
x = np.random.rand(1000)

def row_divide_col_reduce(b, x):
    data = b.data.copy() / np.take(x, b.indices)
    ret = sps.csc_matrix((data, b.indices.copy(), b.indptr.copy()),
                         shape=b.shape)
    return ret.sum(axis=1)

def row_divide_col_reduce_bis(b, x):
    d = sps.spdiags(1.0/x, 0, len(x), len(x))
    return (d * b).sum(axis=1)

In [2]: %timeit row_divide_col_reduce(b, x)
1000 loops, best of 3: 210 us per loop

In [3]: %timeit row_divide_col_reduce_bis(b, x)
1000 loops, best of 3: 697 us per loop

In [4]: np.allclose(row_divide_col_reduce(b, x),
   ...:             row_divide_col_reduce_bis(b, x))
Out[4]: True

如果就地进行除法,则在上面的示例中,您可以将时间减少近一半,即:
def row_divide_col_reduce(b, x):
    b.data /= np.take(x, b.indices)
    return b.sum(axis=1)

In [2]: %timeit row_divide_col_reduce(b, x)
10000 loops, best of 3: 131 us per loop

关于python - 使用scipy.sparse.csc_matrix替代numpy广播,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16043299/

10-12 20:32