Python/NumPy中与num2cell()等效的函数是什么?

3

我很不幸地需要将一些 MATLAB 代码转换为 Python 代码,使用 numpy 数组。

关于 num2cell(),是否有任何共识呢?

个人认为这与 Python/numpy 的语法不符。其思想是这样的:

使用 num2cell,您将得到一个类似于以下的数组

array([[0],[1],[2],[3],[4],[5],[6],[7],[8]])

请参阅 MathWorks 文档

您可以在 numpy 中使用列表推导式来完成此操作:

matlab_lunacy = np.array([[x] for x in range(0, 9)]

但为什么MATLAB用户要使用这种数据结构呢?

NumPy有什么等价物吗?


num2cell() 在分割数据方面非常有用。它允许您轻松切片任何多维数组为各个部分,便于随后的操作。您可以将其切片,使得您可以获得行的列表、列的列表等等,甚至是任意块的列表。 - Rody Oldenhuis
6
在MATLAB中,单元格通常用于非规则(非类似矩阵)的数据结构,例如不同大小向量的序列或字符串序列。Python的等价物是对象的本地列表(或字典)。 - Łukasz Rogalski
1
我们的回答有帮到你吗? - rayryeng
5个回答

4
在早期的MATLAB版本(大约v.3.0左右),只有一种数据结构,即矩阵。它可以包含数字或字符,并且始终是二维的。
后来加入了单元格(Cells)以包含更一般的对象,包括矩阵和字符串。但它们仍然是二维的。
Python有列表(lists),它们是一维的,但可以包含任何东西。numpy是在Python上构建的,添加了多维数组。但列表仍然可用。
因此,将数组转换为列表的任何方法都可能等同于num2cell - 不完全相同,但具有重叠的功能。
In [246]: A=np.arange(24).reshape(2,3,4)   # 3d array
    将数组放入列表中,得到一个由两个数组(2维)组成的列表:
In [247]: B=list(A)
In [248]: B
Out[248]: 
[array([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]]), 
 array([[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]])]

tolist 方法将完全转换为列表(嵌套)。

In [249]: C=A.tolist()
In [250]: C
Out[250]: 
[[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]],
 [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]

list(A)并不常用,当需要使用 tolist 时可能会错误地使用它。

np.split(A,...)B 类似,但子数组仍为三维数组。

unpacking 甚至可以使用,基本上是因为 A 是可迭代的,[a for a in A] 在第一维上分割了 A

In [257]: a,b=A
In [258]: a
Out[258]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

有一个对象dtype,它允许您在数组中放置对象,包括其他数组。但正如许多SO问题所示,构建这些数组可能会很棘手。np.array试图构造最高维度的数组。您需要执行一些技巧来避免这种情况。

In [259]: Z=np.empty((2,),dtype=object)
In [260]: Z
Out[260]: array([None, None], dtype=object)
In [261]: Z[0]=A[0]
In [262]: Z[1]=A[1]
In [263]: Z
Out[263]: 
array([ array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]]),
       array([[12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23]])], dtype=object)

================

在Octave会话中:

>> anum = [1,2,3,4]
anum =

   1   2   3   4

>> acell = num2cell(anum)
acell =
{
  [1,1] =  1
  [1,2] =  2
  [1,3] =  3
  [1,4] =  4
}
>> save -7 test.mat anum acell

scipy.io.loadmat 版本

In [1822]: data = io.loadmat('../test.mat')
In [1823]: data
Out[1823]: 
{'__globals__': [],
 '__header__': b'MATLAB 5.0 MAT-file, written by Octave 4.0.0, 
     2016-10-27 00:59:27 UTC',
 '__version__': '1.0',
 'acell': array([[array([[ 1.]]), array([[ 2.]]), array([[ 3.]]),
      array([[ 4.]])]], dtype=object),
 'anum': array([[ 1.,  2.,  3.,  4.]])}

matrix会被呈现为一个二维数组;cell则是一个对象类型的二维数组,包含了另外的二维数组。


不错。我不知道 tolist 的存在。比我的递归实现要好。 - rayryeng

2

num2cell的作用是将数组中的每个元素分别呈现为单独的单元格,组成一个单元格矩阵。在Python中,与单元格数组相对应的是列表。因此,如果您真的想在Python中创建一个类似于num2cell的方法,您需要创建一个与您的Python NumPy数组具有相同维度的列表,并确保该列表中的每个元素都放在正确的位置上。下面的代码可以实现此功能:

import numpy as np

def num2cell(a):
    if type(a) is np.ndarray:
        return [num2cell(x) for x in a]
    else:
        return a         

这个函数会递归地遍历 NumPy 数组的每个维度。对于数组中每个维度的元素,如果该元素也是一个数组,则对下一维的每个元素进行转换并转换为列表表示。当我们实际遇到一个数字时,这就是基本情况,此时只需返回该数字即可。
下面是在 Python 工作区定义 num2cell 后的工作示例:
In [26]: import numpy as np

In [27]: A = np.random.rand(4,3,3)

In [28]: B = num2cell(A)

In [29]: A[0]
Out[29]:
array([[ 0.52971132,  0.91969837,  0.77649566],
       [ 0.51080951,  0.8086879 ,  0.61840573],
       [ 0.7291165 ,  0.0492292 ,  0.53997368]])

In [30]: B[0]
Out[30]:
[[0.52971132352406691, 0.91969837282865874, 0.77649565991300817],
 [0.51080951338602765, 0.80868789862631529, 0.61840573261134801],
 [0.72911649507775378, 0.049229201932639577, 0.53997367763478676]]

In [31]: A[1][1]
Out[31]: array([ 0.41724412,  0.94679946,  0.79899245])

In [32]: B[1][1]
Out[32]: [0.41724411973558406, 0.9467994633124529, 0.7989924496851234]

我们可以看到这里 B 是 NumPy 数组 A 的列表表示形式。

A.tolist()将会给你一个几乎和num2cell(A)相同的结果,唯一的区别是每个元素将会是Python本地的float而不是np.float64 - ali_m
@ali_m 我意识到了。我在hpaulj的帖子中留了评论。基本上是说我不知道 tolist() 的存在 :) - rayryeng
@ali_m 一点也不。我可能应该编辑我的帖子以反映出来。我非常感谢您的评论。 - rayryeng

1

这取决于代码的其他部分在做什么。一般来说,Matlab使用单元格来表示数组的数组,其中内部数组可以具有不同的大小和形状。

回答你的问题,我认为你所做的基本上就是你想做的,即创建一个数组的数组。


1

.astype(np.object_) 很可能是你需要的东西。考虑一下这个 Matlab 代码:

x = [1 2 3 4]
y = num2cell(x)
y(end) = 'hello'

在NumPy中,这意味着:
x = np.array([1, 2, 3, 4])
y = x.astype(np.object_)
y[-1] = 'hello'

-2

设置过程比较复杂,因为你需要将库链接在一起,但指南写得非常好。一旦安装完毕,导入import matlab.engine并定义eng = matlab.engine.start_matlab()就像这样简单了。现在,你可以调用你自己的matlab函数,例如result = eng.YourFunction(inputs) - Nicky Mattsson
2
该接口旨在在MATLAB和Python之间进行通信,因此仍需要有效的MATLAB许可证和已启动的MATLAB服务器。通常情况下,代码会被移植,例如当您没有购买MATLAB许可证时。如果您有MATLAB许可证,则只需运行原始代码即可。 - Łukasz Rogalski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接