Search code examples
pythonmatlabscipysparse-matrixdata-conversion

Converting a scipy.sparse matrix into an equivalent MATLAB sparse matrix


I have a scipy.sparse.lil_matrix that I want to feed into a MATLAB method (that is not written by me) using the MATLAB Engine API for Python. The posts I've seen so far are either about how to convert a MATLAB sparse matrix into a python equivalent or they require modifying the matlab code which I'd rather circumvent.


Solution

  • Internally I believe MATLAB use the csc like format. But construction is (at least when I used it years ago) with coo style inputs - data, rows, cols.

    I'd suggest making a sparse matrix in MATLAB, and saving it (in the pre-HDF5 mode) to a .mat. Then load that with scipy.io.loadmat. Then use that result as guide when writing a scipy.sparse matrix back to a .mat.

    scipy.sparse has a save function, but it uses the np.savez to write the respective attribute arrays. If you had MATLAB code that could handle .npy files, you probably could load such a save (again using the coo format).

    ===

    A test.

    Create and save a sparse matrix:

    In [263]: from scipy import io, sparse                                                                          
    In [264]: M = sparse.random(10,10,.2,'coo')                                                                     
    In [265]: io.savemat('sparse.mat', {'M':M})       
    

    test load on Python side:

    In [268]: io.loadmat('sparse.mat')                                                                              
    Out[268]: 
    {'__header__': b'MATLAB 5.0 MAT-file Platform: posix, Created on: Wed Jul  3 11:41:23 2019',
     '__version__': '1.0',
     '__globals__': [],
     'M': <10x10 sparse matrix of type '<class 'numpy.float64'>'
        with 20 stored elements in Compressed Sparse Column format>}
    

    So savemat converted the coo format to csc before saving.

    In an Octave session:

    >> load sparse.mat
    >> M
    M =
    
    Compressed Column Sparse (rows = 10, cols = 10, nnz = 20 [20%])
    
      (4, 1) ->  0.41855
      (6, 1) ->  0.33456
      (7, 1) ->  0.47791
      (4, 3) ->  0.27464
      (2, 4) ->  0.96700
      (3, 4) ->  0.60283
      (10, 4) ->  0.41400
      (1, 5) ->  0.57004
      (2, 5) ->  0.44211
      (1, 6) ->  0.63884
      (3, 7) ->  0.012127
      (8, 7) ->  0.77328
      (8, 8) ->  0.25287
      (10, 8) ->  0.46280
      (1, 9) ->  0.0022617
      (6, 9) ->  0.70874
      (1, 10) ->  0.79101
      (3, 10) ->  0.81999
      (6, 10) ->  0.12515
      (9, 10) ->  0.60660
    

    So it looks like the savemat/loadmat code handles sparse matrices in a MATLAB compatible way.