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.
source to share
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)
source to share
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.
source to share