Converting matlab.double array to python array

I am using the python matlab engine to access data from my matlab projects in python. This works pretty well, but I have a problem to use matlab arrays efficiently in python. For example, I want an array from matlab, I use (eng stands for matlab engine):

x = eng.eval(arg)

      

I get a matlab.double array that looks like this:

matlab.double([[1.0,2.0],[4.0,3.0],[2.0,5.0]])

      

Doesn't look too bad. Try to catch the entry:

>>> x[2][1]
5.0

      

Hooray! How about a full line?

>>> x[0]
matlab.double([1.0,2.0])

      

.. well, at least it's a string, but I didn't find the "matlab.double" prefix .. what about a column?

>>> x[:][0]
matlab.double([1.0,2.0])

      

Wait what? I am trying to select all the rows and then the first item from each, but I only get a row instead. And actually:

x[i] == x[:][i] == x[i][:]

      

So basically there are two problems: row selection brings me the unwanted "matlab.double" prefix, and column selection (personally more important) doesn't work at all. Any suggestions here? What I did now was to re-read each value for myself and store it in a new python array:

c = [[] for _ in range(len(x[0]))]
for i in range(len(x[0])):
    for j in range(len(x)):
        c[i].append(x[j][i])

      

It works, but there is one catch: it really slows down the code as the data grows. And of course it's not very pleasant to re-read every entry if they are actually already stored in x.

Thanks for reading this long text, I'm just guessing I'll explain a little more because maybe only a few people are working with the matlab python engine.

+3


source to share


2 answers


The more general approach I'm using now also allows me to round the values ​​if necessary (careful, but rounding takes longer):



from math import log10, floor

def convert(self, x, ROUND=0):

    conv = []

    for _ in range(x.size[0]):
        lst = x._data[_::x.size[0]].tolist()

        if ROUND is not 0:
            lst = [self.round_sig(elem, ROUND) if elem != 0 and
                   elem == elem else elem for elem in lst]

        conv.append(lst)

    return conv

def round_sig(self, x, sig=2):
    return round(x, sig-int(floor(log10(abs(x))))-1)

      

+2


source


Given the discussion below, I was able to find a sane way:

c = []
for _ in range(x.size[1]):
    c.append(x._data[_*x.size[0]:_*x.size[0]+x.size[0]].tolist())
return c

      

So the command takes about 0.009s instead of 0.045s. The zip function usage was around 0.022. Thank you very much, the code is 5x faster!



For clarification: x.size[i]

gives the size of the array matlab.double

. x._data

gives a one-dimensional array of type:

array('d', [1.0,2.0,4.0 ... ])

      

So it includes a tolist () method to get the actual list I want.

+1


source







All Articles