我有一个维度任意的ndarray A
。我想创建一个元组(即数组或列表)的数组B
,其中每个元组的前N
个元素是索引,最后一个元素是在A
中该索引处的值。
例如:
A = array([[1, 2, 3], [4, 5, 6]])
那么,
B = [(0, 0, 1), (0, 1, 2), (0, 2, 3), (1, 0, 4), (1, 1, 5), (1, 2, 6)]
在NumPy中,最好/最快的方法是什么,可以避免使用for
循环?
我有一个维度任意的ndarray A
。我想创建一个元组(即数组或列表)的数组B
,其中每个元组的前N
个元素是索引,最后一个元素是在A
中该索引处的值。
例如:
A = array([[1, 2, 3], [4, 5, 6]])
B = [(0, 0, 1), (0, 1, 2), (0, 2, 3), (1, 0, 4), (1, 1, 5), (1, 2, 6)]
在NumPy中,最好/最快的方法是什么,可以避免使用for
循环?
np.ndenumerate
(使用np.ndenumerate
)。>>> import numpy as np
>>> A = np.array([[1, 2, 3], [4, 5, 6]])
>>> [(*idx, val) for idx, val in np.ndenumerate(A)]
[(0, 0, 1), (0, 1, 2), (0, 2, 3), (1, 0, 4), (1, 1, 5), (1, 2, 6)]
如果你希望它能同时适用于Python 3和Python 2,那么情况会有些不同,因为Python 2不允许在元组字面量内部使用可迭代对象拆包。但是你可以使用元组连接(加法):
>>> [idx + (val,) for idx, val in np.ndenumerate(A)]
[(0, 0, 1), (0, 1, 2), (0, 2, 3), (1, 0, 4), (1, 1, 5), (1, 2, 6)]
np.mgrid
创建索引:>>> grid = np.mgrid[:A.shape[0], :A.shape[1]] # indices!
>>> np.stack([grid[0], grid[1], A]).reshape(3, -1).T
array([[0, 0, 1],
[0, 1, 2],
[0, 2, 3],
[1, 0, 4],
[1, 1, 5],
[1, 2, 6]])
然而,这将需要循环将其转换为元组列表... 但将其转换为列表也很容易:
>>> np.stack([grid[0], grid[1], A]).reshape(3, -1).T.tolist()
[[0, 0, 1], [0, 1, 2], [0, 2, 3], [1, 0, 4], [1, 1, 5], [1, 2, 6]]
列表元组也可以不使用可见的for
循环:
>>> list(map(tuple, np.stack([grid[0], grid[1], A]).reshape(3, -1).T.tolist()))
[(0, 0, 1), (0, 1, 2), (0, 2, 3), (1, 0, 4), (1, 1, 5), (1, 2, 6)]
尽管在Python层中没有可见的for
-loop,但tolist
、list
、tuple
和map
在Python层中隐藏了一个for
-loop。
对于任意维数组,你需要稍微改变后一种方法:
coords = tuple(map(slice, A.shape))
grid = np.mgrid[coords]
# array version
np.stack(list(grid) + [A]).reshape(A.ndim+1, -1).T
# list of list version
np.stack(list(grid) + [A]).reshape(A.ndim+1, -1).T.tolist()
# list of tuple version
list(map(tuple, np.stack(list(grid) + [A]).reshape(A.ndim+1, -1).T.tolist()))
< p > ndenumerate
方法适用于任何维度的数组,而且根据我的计时只会慢2-3倍。
np.ndindex
来完成这个操作,尽管@Mseifert的方法在时间和简洁性方面都是无与伦比的。 这里唯一的循环是将坐标生成器与实际值一起压缩的过程。(与其他答案中相同。)def tuple_index(a):
indices = np.ndindex(*a.shape)
return [(*i, j) for i, j in zip(indices, a.flatten())]
print(tuple_index(a))
[(0, 0, 1), (0, 1, 2), (0, 2, 3), (1, 0, 4), (1, 1, 5), (1, 2, 6)]
mgrid
方法)。 - MSeifertfor
循环实现。但要小心,我认为这两种方法都不会很“快”。 - MSeifertndenumerate
方法。这种方法最多会慢2-3倍,但适用于任何维度。而且它实际上是非常干净和易于理解的代码。 - MSeifert