使用nditer进行浅层迭代

1 投票
2 回答
2753 浏览
提问于 2025-04-18 15:45

我有一个这样的数组:

>>>y = np.random.randint(0, 255, (2,2,3))
>>>array([[[242, 14, 211],
           [198,  7,   0]],

          [[235,  60,  81],
           [164,  64, 236]]])

我需要逐个处理每个三元组元素(不幸的是,这里不能用向量化的方法来解决...)。所以我试着这样做:

for i, j in np.nditer(y):
print y[i, j],

希望能得到这样的输出:

[242, 14, 211], [198, 7, 0], [235, 60, 81], [164, 64, 236],但没有成功!

我遇到了这个错误:

Traceback (most recent call last):

  File "<ipython-input-21-a336ef837a8a>", line 1, in <module>
    for i, j in np.nditer(y):    print y[i,j]

TypeError: iteration over a 0-d array

我很确定我犯了一个很明显的错误... 有谁能帮帮我吗?

2 个回答

4

或者重新调整一下 y 的形状

for i in y.reshape(-1,3):
    print i

双重循环也可以用:

for x in y:
    for z in x:
        print z

普通的 nditer 会遍历 y 中的每一个元素(nditer 不会给你索引):

for i in np.nditer(y):
    print i   
    # wrong y[i]

如果你想遍历 nditer 的两个维度,你需要更深入地了解一些标志和文档。虽然 nditer 提供了底层的迭代机制,但通常情况下你不需要使用它——除非你在做一些不寻常的事情,或者想用 cython 加速代码。


下面是一个从 nditer 对象中获取两个值的例子。每个 op 列表中的数组都有一个值。xz 都是 () 形状的数组。

for x,z in np.nditer([y,y]):
    print x,z

关于 nditer 的更多内容可以在 http://docs.scipy.org/doc/numpy/reference/arrays.nditer.html 找到


这个文档页面有一个使用 external_loop 的例子,它会把数组分成子数组,而不是一个一个地处理。我可以通过重新排列 y 的轴来实现同样的效果:

y3=y.swapaxes(2,0).copy(order='C')
for i in np.nditer(y3,order='F',flags=['external_loop']):
    print i,

[242  14 211] [198   7   0] [235  60  81] [164  64 236]

所以我们可以用 nditer 来进行这种浅层迭代,但这样做值得吗?


迭代 numpy 数组的前 d 轴 中,我发现了 ndindex

for i in np.ndindex(y.shape[:2]):
    print y[i],
# [242  14 211] [198   7   0] [235  60  81] [164  64 236]

ndindex 是基于 nditer 的。生成浅层迭代的诀窍是使用只包含你想要迭代的维度的子数组。

class ndindex(object):
    def __init__(self, *shape):
        ...
        x = as_strided(_nx.zeros(1), shape=shape, strides=_nx.zeros_like(shape))
        self._it = _nx.nditer(x, flags=['multi_index', 'zerosize_ok'], order='C')
    def __next__(self):
        next(self._it)
        return self._it.multi_index

或者提取 ndindex 的基本部分,我得到了:

xx = np.zeros(y.shape[:2])
it = np.nditer(xx,flags=['multi_index'])                               
while not it.finished:
    print y[it.multi_index],
    it.iternext()
# [242  14 211] [198   7   0] [235  60  81] [164  64 236]
1

看起来你只需要把这个结构压平一层。你可以使用itertools里的chain操作符。

from itertools import chain    


y = np.random.randint(0, 255, (2,2,3)
b = chain.from_iterable(y) # where b is a generator

list(b) 的输出

[array([ 51, 119,  84]),
 array([ 50, 110, 193]),
 array([165, 157,  52]),
 array([239, 119,  83])]

撰写回答