gpt4 book ai didi

python - 将具有形状 (M, N, P) 数组的 numpy int 数组高效转换为具有 (N, P) 形状的二维对象数组

转载 作者:太空宇宙 更新时间:2023-11-03 11:22:35 25 4
gpt4 key购买 nike

从一个数据类型为 int 的形状为 (M, N, P) 的 3D 数组,我想得到一个数据类型为 的形状为 (N, P) 的二维数组object 并以合理的效率完成此操作。

我很高兴对象是 tuplelistnumpy.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 数组时能够判断应该有多少维度:

a2 = np.array(m.transpose(1,2,0), astype=object, ndim=2)

Numpy 知道如果嵌套迭代在第三个维度上有不同的形状(在本例中),则在最终深度之前停止,但由于 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] 是完全合法的。然而,这三种更合理的尝试都没有奏效。

最佳答案

所以对于较小的 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) 变成形状 (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()

我可以先转置,然后 reshape ,m.transpose(1,2,0).reshape(-1,2)

为了获得元组,我需要通过推导传递 reshape 的数组:

a2.ravel()[:] = [tuple(l) for l in m.reshape(2,-1).T]

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

m.transpose(1,2,0).astype(object) 仍然是 3d;它只是用指向整数的指针更改了整数。数组维度和 dtype 之间有一堵“墙”。 reshape 和 transpose 之类的东西只在维度上操作,不会穿透那堵墙,也不会移动它。列表是一直向下的指针。对象数组仅在 dtype 级别使用指针。

不要害怕 a2.ravel()[:]= 表达式。 ravel 是一种廉价的 reshape ,分配给数组的扁平版本实际上可能比分配给二维版本更快。毕竟,数据(在本例中为指针)存储在平面数据缓冲区中。

但是(玩了一会儿之后)我可以在没有 ravel 或 reshape 的情况下完成分配(仍然需要 tolist 来移动 object 边界)。列表嵌套必须匹配 a2 形状直至“对象”级别。

a2[...] = m.transpose(1,2,0).tolist()   # even a2[:] works

(这让人想起关于给 np.array 一个 maxdim 参数的讨论 - Prevent numpy from creating a multidimensional array)。

tolist 的使用似乎效率低下。但是,如果 a2 的元素是元组(或者更确切地说是指向元组的指针),则必须以某种方式创建这些元组。 mc 数据缓冲区不能被视为一组元组。 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)

从而避免列表理解。它不一定更简单或更快。

关于python - 将具有形状 (M, N, P) 数组的 numpy int 数组高效转换为具有 (N, P) 形状的二维对象数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39876136/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com