简体   繁体   中英

sparse matrix: Matlab to Python code conversion

How should I convert this from Matlab into Python:

A = sparse(row_idx, col_idx, values, len, s1 * s2);
scales = zeros(size(A, 1), 1);
scales(sub2ind([s1 s2], floor(frames(2, :)), floor(frames(1, :)))) = ...
    frames(3, :);
eq = A \ scales;

My attempt is:

from scipy.sparse import csr_matrix # to replace sparse matrix
import numpy as np # to replace \ with np.linalg.lstsq
A = csr_matrix((values, (row_idx , col_idx )), shape=(length, width * height))
scales = np.zeros((A.shape[0]));
for kp in kps:
   x,y = int(kp.pt[0]), int(kp.pt[1])
   scales[y][x] = int(kp.size) # error
   scales[y*x] = int(kp.size) # again, error:(
...
eq = np.linalg.lstsq(A, scales)

I changed variables names ( len -> length , (s1,s2) -> (width, height) ), and accesses size member in the keypoint class instead of frames[3] in matlab, but these are minor changes.

What I'm not sure, is what exactly should I do with the scales creation and index access. I seem to miss something but can't find what.

I get TypeError: 'numpy.float64' object does not support item assignment which doesn't surprise me since scales is 1-dim array and I shouldn't access it with [][] .

However, changing it to scales[y*x] = int(kp.size) raises the following: LinAlgError: 0-dimensional array given. Array must be two-dimensional LinAlgError: 0-dimensional array given. Array must be two-dimensional .


From what I understand, the Matlab code takes a sparse matrix, creates a column vector ( scales ) which is then populated such that any index (x,y) from frame (ie index of every frame (= keypoint in my Python code)) and inserts a new value at said index (the value is size of frame(3) ). Seems easy enough but I don't know where I'm going wrong.

Any help would be much appreciated, Thanks :)

The problem is the np.linalg.lstsqr is a numpy function, and doesn't understand sparse matrices. Numpy function work if they delegate the job to the methods, but not if they first try to turn the sparse matrix into an array.

For a simple example:

In [345]: R = np.arange(1,6)
In [346]: M = sparse.csr_matrix(([1,1,1],([0,2,4],[0,1,2])),shape=(5,3))
In [347]: M.A
Out[347]: 
array([[1, 0, 0],
       [0, 0, 0],
       [0, 1, 0],
       [0, 0, 0],
       [0, 0, 1]], dtype=int64)

In [348]: np.linalg.lstsq(M,R, rcond=None)
   ...
-> 1977     _assertRank2(a, b)
   1978     _assertNoEmpty2d(a, b)  # TODO: relax this constraint
   1979     m  = a.shape[0]

/usr/local/lib/python3.6/dist-packages/numpy/linalg/linalg.py in _assertRank2(*arrays)
    193         if a.ndim != 2:
  ....
LinAlgError: 0-dimensional array given. Array must be two-dimensional

It thinks the dimension of M is 0-d, not 2-d. That's because, a sparse matrix when wrapped in np.array (or `asarray), produces a 0d object array:

In [351]: np.array(M)
Out[351]: 
array(<5x3 sparse matrix of type '<class 'numpy.int64'>'
    with 3 stored elements in Compressed Sparse Row format>, dtype=object)
In [352]: _.shape
Out[352]: ()

The correct way is to turn the sparse matrix into a dense with its own method:

In [354]: np.linalg.lstsq(M.A,R, rcond=None)
....
Out[354]: (array([1., 3., 5.]), array([20.]), 3, array([1., 1., 1.]))

In MATLAB sparse matrices are integrated into the main code. In numpy , they are in a separate scipy.sparse package. A sparse matrix is not subclass of np.ndarray .

There is a sparse linear algebra subpackage:

In [355]: from scipy.sparse import linalg as spla
In [356]: spla.lsqr(M, R)
Out[356]: 
(array([1., 3., 5.]),
 2,
 1,
 4.47213595499958,
 4.47213595499958,
 1.0,
 1.0,
 4.082652109348718e-16,
 5.916079783099617,
 array([0., 0., 0.]))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM