【问题标题】:Convert matlab.double array to python array将 matlab.double 数组转换为 python 数组
【发布时间】:2015-07-12 21:04:18
【问题描述】:

我正在使用 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 引擎。

【问题讨论】:

  • x[:] 只是复制 x,所以行为符合预期
  • 哦,谢谢 - 我不知道。但是为什么 x[a][b] 有效,例如 x[0:1][1] 给出索引错误(x[0:1] 有效)?
  • x[0:1] 的长度为 1,因此唯一有效的索引是 0。用 Python 列表试试吧。
  • 你应该问的问题是,“我如何有效地提取一列?”
  • 哇,这个问题帮了大忙——我现在遇到了多种遇到这个问题的方法。例如,这一次削减了一半的时间for _ in zip(*x): a.append(_) 然而,对于 for 循环来说,这仍然是相当多的时间。我还设法通过简单的方式更快地获得列:x[0::len(x[0])],但随后我遇到了开始的问题:如何删除“matlab.double(”前缀/附件?

标签: python arrays performance matlab multidimensional-array


【解决方案1】:

有一种更简洁(和 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]

【讨论】:

    【解决方案2】:

    根据下面讨论的输入,我设法找到了一种合理的方法:

    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() 方法来获取我需要的实际列表。

    【讨论】:

    • 这行得通,但我认为它应该是“x.size[1]”(没有“-1”)?当我尝试上面的代码时,我从数组中丢失了一个元素。
    • 你确实是对的,不知道这是从哪里来的。无论如何,我现在使用的是更通用的方法,它允许我与输入的值具有相同的类型,我将在下一个答案中发布。
    【解决方案3】:

    一种更通用的方法,我现在正在有效地使用它,还允许我在需要时对值进行四舍五入(不过要小心,四舍五入需要更多的计算时间):

    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)
    

    【讨论】:

      猜你喜欢
      • 2017-02-11
      • 1970-01-01
      • 2015-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-26
      • 1970-01-01
      相关资源
      最近更新 更多