【问题标题】:How can I translate a MATLAB cell in Python 3?如何在 Python 3 中翻译 MATLAB 单元格?
【发布时间】:2017-07-04 07:33:31
【问题描述】:

只是给你一些背景:

我必须将一些 MATLAB 代码翻译成 Python 3,但在这里我遇到了一个小问题。

Matlab:

for i in 1:num_nodes
    for j in 1:num_nodes
        K{i,j} = zeros(3,3);

我翻译成的:

k_topology = [[]]
for i in range(x):
    for i in range(x):
        k_topology[[i][j]].extend(np.zeros(3,3))

另外,在 Matlab 代码中还有第三个循环:

for k in 1:3
    K{i,j}(k,k) = -1

哪一种……让我不高兴?

事实上,我真的不知道如何将这种变量转换为 Python。另外,我猜我的 Python 代码有点“损坏” - 我并不是真的要求你们中的任何人改进它 - 所以我只是问哪个是最好的如何将 Matlab 的单元格翻译成 Python?


我终于找到了显然简单的翻译方法,使用列表理解 - 根据 kazemakase 的回答。实际的 Python 代码现在如下所示:

k_topology = [[np.zeros((3,3)) for j in range(self.get_nb_nodes_from_network())]\
                  for i in range(self.get_nb_nodes_from_network())]

在输出中看起来像这样:

[[array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.]]), 
array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.]]), 
array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])], ..., [array(...)]]

(这里的值实在太多,无法粘贴,但我想你明白了。)

【问题讨论】:

  • 描述一下 Matlab 代码的作用以及您认为它难以翻译的原因可能会有所帮助。
  • K 矩阵是用来表示电网的拓扑结构的。所以它将包含长度从 1 到最大 3 的其他矩阵。就目前而言,我可以理解第一个循环(带有 K{i,j} 的那个),但在我看来第二个循环真的很奇怪:什么是 K{i,j}(k,k)?我该如何翻译它?这就是我觉得很难的原因:我就是不明白
  • 所以K 是二维的?那么k_topologyK 之间有什么区别?
  • 我认为最接近的是np.array of dtype=object
  • 是的,我忘了说:k_topology 是我的 Python 等价于 Matlab 的 K 矩阵

标签: python matlab numpy scipy


【解决方案1】:

您需要问的第一个问题是“什么 Matlab 单元格,什么是合适的相应 Python 类型?”

如果我从我糟糕的旧 Matlab 时代没记错的话,单元格是一种包含混合类型内容的容器。它类似于动态类型的数组或矩阵。它是多维索引的。

Python 是动态类型的,所以任何 Python 的 contianer 基本上都可以实现这个功能。 Python 中的列表是索引的,因此嵌套列表可以工作 - 但设置和访问它们有点奇怪:

K = [[None] * num_nodes  for _ in range(num_nodes)]
K[i][j]  # need two indices to access elements of a nested list.

对于特定场景,字典更好地反映了 Matlab 语法。虽然字典只需要一个索引,但我们可以利用这样一个事实,即可以不带括号声明元组,并且字典可以将元组作为索引:

K = {}
for i in range(num_nodes):
    for j in range(num_nodes):
        K[i, j] = np.zeros((3, 3))

        for k in 1:3
            K[i, j][k, k] = -1

虽然字典在语法上更简洁,但元素访问的性能可能不如嵌套列表。嵌套看起来与 Matlab 代码不同。选择取决于性能或与原始代码的相似性。但是,如果性能是一个问题,那么无论如何都要考虑更多的事情。总而言之:没有一种最好的方法。


由于 OP 明确要求不要改进代码,我明确要求他/她忽略这部分答案。

构建对角矩阵的更好方法是使用np.ones,而不是循环遍历对角元素。

K = {}
for i in range(num_nodes):
    for j in range(num_nodes):
        K[i, j] = -np.ones((3, 3))

此外,嵌套列表可以在没有(大量)事先初始化的情况下构建,如果这是首选方法:

K = []
for i in range(num_nodes):
    K.append([])
    for j in range(num_nodes):
        K[-1].append(-np.ones((3, 3)))

现在,为了我的灵魂安宁,让我拆开提供有关 OP 代码的反馈:

k_topology = [[]]
for i in range(x):
    for i in range(x):
        k_topology[[i][j]].extend(np.zeros(3,3))
  1. 这与原Matlab代码无关(变量名不同)
  2. 两个循环都使用ij 从未定义过。
  3. [[i][j]] 用一个元素 i 构建一个列表,并尝试获取第 j 个元素。如果 j 不是 0,则会导致错误。
  4. list.extend a 将参数的所有元素单独附加到列表中 - 在本例中为单独的行。 list.append 可以正确使用,因为整个 3x3 矩阵应该作为一个元素附加到 K 中。
  5. np.zeros(3, 3) 应该是 np.zeros((3, 3))(假设 npnumpy 的别名),因为函数的形状是第一个参数,而不是多个参数。

【讨论】:

  • 嗯,谢谢你的回答,这让我明白了很多!所以我想我要检查涉及嵌套列表的那个。
【解决方案2】:

使用我在链接帖子中演示的 Octave/scipy save/loadmat:

在 Octave 会话中

>> num_nodes=3
num_nodes =  3
>> num_nodes=3;
>> K=cell(num_nodes, num_nodes);
>> for i = 1:num_nodes
   for j = 1:num_nodes
      K{i,j} = zeros(2,2);
   end
end

>> K
K =
{
  [1,1] =

     0   0
     0   0

  [2,1] =

     0   0
     0   0
etc

访问一个单元格:

>> K{1,2}
ans =

   0   0
   0   0

访问一个单元格的一个元素:

>> K{1,2}(1,1)
ans = 0

>> save -7 kfile.mat K

在 Python 中

In [31]: from scipy import io
In [32]: data = io.loadmat('kfile.mat')
In [34]: data
Out[34]: 
{'K': array([[array([[ 0.,  0.],
        [ 0.,  0.]]),
         array([[ 0.,  0.],
        [ 0.,  0.]]),
         array([[ 0.,  0.],
        [ 0.,  0.]])],
        [array([[ 0.,  0.],
        [ 0.,  0.]]),
         array([[ 0.,  0.],
        [ 0.,  0.]]),
         array([[ 0.,  0.],
        [ 0.,  0.]])],
        [array([[ 0.,  0.],
        [ 0.,  0.]]),
         array([[ 0.,  0.],
        [ 0.,  0.]]),
         array([[ 0.,  0.],
        [ 0.,  0.]])]], dtype=object),
 '__globals__': [],
 '__header__': b'MATLAB 5.0 MAT-file, written by Octave 4.0.0, 2017-02-15 19:05:44 UTC',
 '__version__': '1.0'}

In [35]: data['K'].shape
Out[35]: (3, 3)
In [36]: data['K'][0,0].shape
Out[36]: (2, 2)
In [37]: data['K'][0,0][0,0]
Out[37]: 0.0

loadmatcell 视为 2d 对象 dtype 数组;而正则矩阵是二维数值数组。对象数组在很多方面类似于嵌套的 Python 列表。

【讨论】:

  • 谢谢。我终于用列表推导解决了我的问题,但我没有使用 Octave,所以我认为你的答案与我的问题无关
  • Octave 与 Matlab 兼容。我正在说明 Matlab 结构和 numpy 结构之间最直接的等价关系。但是直接创建一个二维对象数组有点尴尬,在你的情况下可能不需要。列表在 python 中更自然/原生。
猜你喜欢
  • 2012-09-09
  • 2017-11-24
  • 2017-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多