Search code examples
pythonnumpyscipysparse-matrix

Element-wise operations on scipy.sparse.coo_matrix (e.g. modulo)?


How can I perform element-wise operations (e.g. modulo) for a scipy.sparse.coo_matrix?

Do I have to create a NumPy dense array from it? If that's the case won't I lose all the benefits gained from creating a sparse matrix?


Solution

  • As long as the element-wise operation does not change the sparsity of the data, you can use the .data attribute, e.g.:

    import scipy as sp
    import scipy.sparse
    
    
    m = (sp.sparse.rand(5, 10, 0.2) * 100).astype(int)
    print(m)
    
      (1, 0)        34
      (1, 2)        2
      (2, 2)        39
      (1, 4)        54
      (3, 4)        22
      (4, 4)        46
      (1, 6)        40
      (1, 7)        97
      (4, 8)        60
      (4, 9)        97
    
    m.data %= 10
    print(m)
    
      (1, 0)        4
      (1, 2)        2
      (2, 2)        9
      (1, 4)        4
      (3, 4)        2
      (4, 4)        6
      (1, 6)        0
      (1, 7)        7
      (4, 8)        0
      (4, 9)        7
    

    This should be efficient and should not have any conversion overhead.

    Note that this can be done for any operation for which zero 0 is the absorbing element, at least on one side (left or right) for non-symmetric (commutative) operations.

    For example, in the modulo % operation, 0 is the left-absorbing element, since 0 % a = 0 for any a. The same is true for integer division //, division / (as long as 0.0 and -0.0 distinction is not needed) and exponentiation ** (for positive numbers). For multiplication *, 0 is the absorbing element.

    For the case of element-wise multiplication * and / (by a scalar at least) are supported with the regular syntax by scipy.sparse.coo_matrix objects.