从具有数据类型int
的形状(M,N,P)的3D数组中,我想获得数据类型object
的形状(N,P)的2D数组,并且以合理的效率完成这项工作。
我对tuple
,list
或numpy.ndarray
类型的对象感到满意。
我有一个解决方案的工作黑客,我必须通过列表。所以感觉我错过了一些东西:
import numpy as np
m = np.mgrid[:8, :12]
l = zip(*(v.ravel() for v in m))
a2 = np.empty(m.shape[1:], dtype=np.object)
a2.ravel()[:] = l
在此示例中,最终数组a2
应具有a2[(x, y)] == (x, y)
感觉应该可以转换m
并使a2
像这样:
a2 = m.transpose(1,2,0).astype(np.object).reshape(m.shape[1:])
因为numpy并不真正关心对象内部的内容,或者在创建类型np.object
的numpy-array时能够分辨出应该有多少维度:
a2 = np.array(m.transpose(1,2,0), astype=object, ndim=2)
Numpy知道在嵌套iterables的最终深度之前停止,如果它们在第三维(在这个例子中)具有不同的形状,但由于m
没有不规则性,这似乎是不可能的。
或创建a2
并使用转置后填充:
a2 = np.empty(m.shape[1:], dtype=np.object)
a2[...] = m.transpose(1, 2, 0)
在这种情况下,例如m.transpose(1, 2, 0)[2, 4]
为np.array([2, 4])
,将其分配给a2[2, 4]
本来是完全合法的。但是,这三个更合理的尝试都不起作用。
答案 0 :(得分:1)
对于较小的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)and
np.array(ll)shape is (12,2), then
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)
仍为3d;它只是用整数指针改变整数。阵列尺寸和dtype之间有一个“墙”。重塑和转置之类的东西只能在尺寸上运行,不会穿透那堵墙,也不能移动它。列表一直是指针。对象数组仅在dtype
级别使用指针。
不要害怕a2.ravel()[:]=
表达。 ravel
是一个廉价的重塑,并且对数组的展平版本的赋值实际上可能比分配给2d版本更快。毕竟,数据(在这种情况下是指针)存储在一个平面数据缓冲区中。
但是(在玩了一下之后)我可以在没有ravel或reshape的情况下完成任务(仍然需要tolist
来移动object
边界)。列表嵌套必须将a2
形状与“对象”级别匹配。
a2[...] = m.transpose(1,2,0).tolist() # even a2[:] works
(这会让人想起有关np.array
maxdim
tolist
参数的讨论 - Prevent numpy from creating a multidimensional array)。
使用a2
似乎效率低下。但是如果c
的元素是元组(或者指向元组的指针),则必须以某些方式创建这些元组。 m
的{{1}}数据缓冲区不能被视为一组元组。 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)
从而避免列表理解。它不一定更简单或更快。