因此,对于较小的m
:
In [513]: m = np.mgrid[:3,:4]
In [514]: m.shape
Out[514]: (2, 3, 4)
In [515]: m
Out[515]:
array([[[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2]],
[[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3]]])
In [516]: ll = list(zip(*(v.ravel() for v in m)))
In [517]: ll
Out[517]:
[(0, 0),
(0, 1),
(0, 2),
...
(2, 3)]
In [518]: a2=np.empty(m.shape[1:], dtype=object)
In [519]: a2.ravel()[:] = ll
In [520]: a2
Out[520]:
array([[(0, 0), (0, 1), (0, 2), (0, 3)],
[(1, 0), (1, 1), (1, 2), (1, 3)],
[(2, 0), (2, 1), (2, 2), (2, 3)]], dtype=object)
制造一个正确形状的空白数组,然后通过
[:]=
填充它是控制此类数组的
object
深度的最佳方法。
np.array(...)
默认为最高可能维度,本例中为3d。
因此,主要问题是 - 是否有更好的方法构造包含元组的
ll
列表。
a2.ravel()[:] = np.array(ll)
无法工作,抱怨(12,2) into shape (12)
。
倒推一下,如果我从一个像ll
的数组开始,将其转换为嵌套列表,那么赋值就可以成功,除了a2
的元素是列表而不是元组:
In [533]: a2.ravel()[:] = np.array(ll).tolist()
In [534]: a2
Out[534]:
array([[[0, 0], [0, 1], [0, 2], [0, 3]],
[[1, 0], [1, 1], [1, 2], [1, 3]],
[[2, 0], [2, 1], [2, 2], [2, 3]]], dtype=object)
m
形状为(2,3,4),而
np.array(ll)
的形状为(12,2),那么
m.reshape(2,-1).T
产生相同的结果。
a2.ravel()[:] = m.reshape(2,-1).T.tolist()
我可以先转置,然后再重塑:m.transpose(1,2,0).reshape(-1,2)
。
要获取元组,我需要通过推导将重塑的数组传递:
a2.ravel()[:] = [tuple(l) for l in m.reshape(2,-1).T]
===============
m.transpose(1,2,0).astype(object)
仍然是三维的;它只是用指向整数的指针替换了整数。在数组维度和dtype
之间有一个“墙”。像reshape
和transpose
这样的操作只作用于维度,不穿透或移动该墙。列表从始至终都是指针。对象数组仅在dtype
级别使用指针。
不要害怕a2.ravel()[:]=
表达式。 ravel
是一种廉价的reshape
,将数组的扁平版本分配给可能比分配给二维版本更快。毕竟,数据(在本例中为指针)存储在平坦的数据缓冲区中。
但是(玩弄一下后),我可以在没有ravel
或reshape
的情况下进行赋值(仍然需要tolist
来移动object
边界)。 列表嵌套必须与a2
形状匹配,直到'object'级别。
a2[...] = m.transpose(1,2,0).tolist()
这让我想起了一个关于给np.array
添加maxdim
参数的讨论 - Prevent numpy from creating a multidimensional array。
使用tolist
似乎是一种低效率的方法。但是,如果a2
的元素是元组(或者说是指向元组的指针),那么这些元组必须以某种方式被创建出来。不能将m
的c
数据缓冲区视为一组元组。使用tolist
(带有[tuple...]
推导式)可能是创建这些对象最有效的方法。
==============
我是否提到转置可以索引,从而产生具有正确数字的2个元素数组?
In [592]: m.transpose(1,2,0)[1,2]
Out[592]: array([1, 2])
In [593]: m.transpose(1,2,0)[0,1]
Out[593]: array([0, 1])
由于结构化数组的 tolist
使用元组,因此我可以这样做:
In [598]: a2[:]=m.transpose(1,2,0).copy().view('i,i').reshape(a2.shape).tolist()
In [599]: a2
Out[599]:
array([[(0, 0), (0, 1), (0, 2), (0, 3)],
[(1, 0), (1, 1), (1, 2), (1, 3)],
[(2, 0), (2, 1), (2, 2), (2, 3)]], dtype=object)
因此可以避免列表推导式。这并不一定更简单或更快。