使用scipy.sparse.csc_matrix替换numpy广播

时间:2013-04-16 17:26:16

标签: python numpy scipy sparse-matrix

我的代码中包含以下表达式:

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()将沿错误的轴相加。)

2 个答案:

答案 0 :(得分:7)

如果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

答案 1 :(得分:6)

要实施a = (b / x[:, np.newaxis]).sum(axis=1),您可以使用a = b.sum(axis=1).A1 / xA1属性返回1D ndarray,因此结果是1D ndarray,而不是matrix。这个简洁的表达式有效,因为您可以按{1}} 按轴1进行缩放。例如:

x

更一般地说,如果要使用向量In [190]: b Out[190]: <3x3 sparse matrix of type '<type 'numpy.float64'>' with 5 stored elements in Compressed Sparse Row format> In [191]: b.A Out[191]: array([[ 1., 0., 2.], [ 0., 3., 0.], [ 4., 0., 5.]]) In [192]: x Out[192]: array([ 2., 3., 4.]) In [193]: b.sum(axis=1).A1 / x Out[193]: array([ 1.5 , 1. , 2.25]) 缩放稀疏矩阵的行,可以将左侧的x与对角线上包含b的稀疏矩阵相乘。函数1.0/x可用于创建这样的矩阵。例如:

scipy.sparse.spdiags