Efficiently inversing a `csr_matrix` in `scipy` element-wise

Viewed 52

Let $A$ be a csr_matrix representing the connectivity matrix for a graph where $A_{ij}$ is the weight of an edge. Now, I need to inverse each non-zero element of the matrix in an efficient way. The way I'm doing this right now is

B = 1.0 / A.toarray()
B[B == np.inf] = 0

This has two down-sides:

  1. memory usage increases by converting a csr_matrix to an array.
  2. a division by zero happens

Are there any suggestions to do this more efficient?

2 Answers

One way you could do this is to create a new matrix from the data, indices and indptr of A: B = csr_matrix((1/A.data, A.indices, A.indptr)).

(This assumes that there are no explicitly stored zeros in A, so 1/A.data doesn't result in some values being inf.)

For example,

In [108]: A
Out[108]: 
<4x4 sparse matrix of type '<class 'numpy.float64'>'
    with 4 stored elements in Compressed Sparse Row format>

In [109]: A.A
Out[109]: 
array([[0. , 1. , 2.5, 0. ],
       [0. , 0. , 0. , 0. ],
       [0. , 0. , 0. , 4. ],
       [2. , 0. , 0. , 0. ]])

In [110]: B = csr_matrix((1/A.data, A.indices, A.indptr))

In [111]: B
Out[111]: 
<4x4 sparse matrix of type '<class 'numpy.float64'>'
    with 4 stored elements in Compressed Sparse Row format>

In [112]: B.A
Out[112]: 
array([[0.  , 1.  , 0.4 , 0.  ],
       [0.  , 0.  , 0.  , 0.  ],
       [0.  , 0.  , 0.  , 0.25],
       [0.5 , 0.  , 0.  , 0.  ]])

csr has a power method:

In [598]: M = sparse.csr_matrix([[0,3,2],[.5,0,10]])
In [599]: M
Out[599]: 
<2x3 sparse matrix of type '<class 'numpy.float64'>'
    with 4 stored elements in Compressed Sparse Row format>
In [600]: M.A
Out[600]: 
array([[ 0. ,  3. ,  2. ],
       [ 0.5,  0. , 10. ]])
In [601]: x = M.power(-1)
In [602]: x
Out[602]: 
<2x3 sparse matrix of type '<class 'numpy.float64'>'
    with 4 stored elements in Compressed Sparse Row format>
In [603]: x.A
Out[603]: 
array([[0.        , 0.33333333, 0.5       ],
       [2.        , 0.        , 0.1       ]])
Related