我正在使用 matlab python 引擎来访问 python 中的 matlab 项目中的数据。这工作得很好,但我确实在 python 中有效使用 matlab 数组时遇到问题。例如,我想要一个来自 matlab 的数组,我使用(eng 代表 matlab 引擎):
x = eng.eval(arg)
我得到的是一个 matlab.double 数组,如下所示:
matlab.double([[1.0,2.0],[4.0,3.0],[2.0,5.0]])
看起来还不错。让我们尝试捕获一个条目:
>>> x[2][1]
5.0
耶!整排怎么样?
>>> x[0]
matlab.double([1.0,2.0])
.. 好吧,至少它是一行,但我没有找到“matlab.double”前缀.. 列怎么样?
>>> x[:][0]
matlab.double([1.0,2.0])
等等,什么?我尝试选择所有行,然后选择每行的第一个元素,但我只得到该行。事实上:
x[i] == x[:][i] == x[i][:]
因此,基本上出现了两个问题:选择一行给我带来了不需要的“matlab.double”前缀,而选择列(个人更重要)根本不起作用。这里有什么建议吗? 我现在所做的是重新读取每个值并将其安全地放入一个新的 python 数组中:
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])
这可行,但有一个问题:随着数据的增长,它会极大地减慢代码速度。当然,如果它们实际上已经存储在 x 中,那么重新读取每个条目感觉并不好。
感谢您阅读这篇长文,我只是假设我解释得更多一点,因为可能只有少数人使用 python matlab 引擎。
一种更通用的方法,我现在正在高效地使用它,还允许我在需要时对值进行舍入(但要小心,舍入需要更多的计算时间):
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)
根据下面讨论的输入,我设法找到了一个合理的方法:
c = []
for _ in range(x.size[1]):
c.append(x._data[_*x.size[0]:_*x.size[0]+x.size[0]].tolist())
return c
这样,该命令大约需要 0.009 秒,而不是之前的 0.045 秒。使用 zip 功能大约需要 0.022 秒。非常感谢,代码现在运行速度快了 5 倍!
为了澄清:
x.size[i]
给出了 matlab.double
数组的大小。 x._data
给出类型的一维数组:
array('d', [1.0,2.0,4.0 ... ])
因此它包含一个 tolist() 方法来获取我需要的实际列表。
有一种更简洁(和Pythonic)的方法来使用列表理解来提取列,并且它还可以立即以Python浮点数列表的形式提供输出:
>>> x = matlab.double([[1.0,2.0],[4.0,3.0],[2.0,5.0]])
>>> [d[0] for d in x]
[1.0, 4.0, 2.0]
对于这个问题的新手,
numpy
是正确的选择,你可以选择从那里转换为纯Python列表:
import numpy as np
y = np.asarray(x).tolist()