0
votes

Suppose I have some Scipy sparse csr matrix, A, and a set of indices, inds=[i_1,...,i_n]. I can access the submatrix given by the rows and columns given in inds via A[inds,:][:,inds]. But I cannot figure out how to modify them. All of the following fail (i.e. do not change the matrix values):

  • A[inds,:][:,inds] *= 5.0
  • (A[inds,:][:,inds]).multiply(5.0)
  • A[inds,:][:,inds] = 5.0

Is there any easy way to modify a submatrix of a sparse matrix?

1
Why are you using the [][] style of indexing? Why not just one indexing bracket set?hpaulj
Because A[inds,inds] != A[inds,:][:,inds]. This is just how I learned how to access an entire submatrix.Ben Southworth

1 Answers

3
votes

The rules for accessing a block, or submatrix, in sparse are the same [edit: similar] as for numpy. The 2 index arrays need to be broadcastable. The simplest way is to make the 1st one a column vector.

I'll illustrate:

In [13]: A = np.arange(24).reshape(4,6)

In [14]: M=sparse.csr_matrix(A)

In [15]: A[[[1],[2]],[1,2,3]]
Out[15]: 
array([[ 7,  8,  9],
       [13, 14, 15]])

In [16]: M[[[1],[2]],[1,2,3]].A
Out[16]: 
array([[ 7,  8,  9],
       [13, 14, 15]], dtype=int32)

In [17]: idx1=np.array([1,2])[:,None]

In [18]: idx1
Out[18]: 
array([[1],
       [2]])

In [19]: idx2=np.array([1,2,3])

In [20]: M[idx1, idx2].A
Out[20]: 
array([[ 7,  8,  9],
       [13, 14, 15]], dtype=int32)

In [21]: M[idx1, idx2] *= 2

In [22]: M.A
Out[22]: 
array([[ 0,  1,  2,  3,  4,  5],
       [ 6, 14, 16, 18, 10, 11],
       [12, 26, 28, 30, 16, 17],
       [18, 19, 20, 21, 22, 23]], dtype=int32)

M[inds,:][:,inds] has the same problem in sparse as in numpy. With a list inds, M[inds,:] is a copy of the original, not a view. I've show that with reference to the data buffers in numpy. I'm not quite sure how to demonstate it with sparse.

Roughly, A[...][...] = ... translates to A.__getitem__(...).__setitem__(...,...). If A.__getitem__(...) is a copy, then modifying it won't modify A itself.

Actually sparse matrices don't have distinction between views and copies. Most, if not all, indexing produces a copy. M[:2,:] is a copy, even though A[:2,:] is a view.

I should also add that changing the values of a sparse matrix is something you should do with caution. In place multiplications (*=) is ok.

In place addition is not supported:

In [31]: M[idx1, idx2] += 2
...
NotImplementedError: 

Modification of values may produce an EfficiencyWarning - if it turns a 0 value to nonzero:

In [33]: M[:2, :2] = 3
/usr/lib/python3/dist-packages/scipy/sparse/compressed.py:690: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.
  SparseEfficiencyWarning)

The np.ix_ answer to your previous question works here as well.
Python - list of same columns / rows from matrix

M[np.ix_([1,2],[1,2,3])].A