【问题标题】:shallow iteration with nditer使用 nditer 进行浅迭代
【发布时间】:2014-09-25 14:57:48
【问题描述】:

我有这样一个数组:

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

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

而且我必须遍历每个 triplet 元素(不幸的是,矢量化对我没有帮助......)。所以我尝试了:

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

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

【问题讨论】:

    标签: python numpy iteration


    【解决方案1】:

    或重塑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 的标志和文档,以迭代其2 个维度。虽然nditer 提供了对底层迭代机制的访问权限,但您通常不需要使用它——除非您正在做一些不寻常的事情,或者尝试使用cython 加速代码。


    这是一个从 nditer 对象的迭代中获取 2 个值的示例。 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 的示例,该示例将数组放入子数组中,而不是单独列出。我可以通过重新排序其轴来完成 3d 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 来做这个浅层迭代,但这值得吗?


    Iterating over first d axes of numpy array,我偶然发现了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]
    

    【讨论】:

    • 感谢一次 2 个元素的技巧! :-) 它仍然在数组的每个元素上进行迭代,但是......我会看看我是否可以将它调整为可以满足我需求的东西。
    • “一次 2 个元素”的技巧就像 Python zip,一种同步遍历 2 个或更多数组的方法,因此您可以将它们组合起来,例如x+z。您想要的是来自一个数组的 N 个项目块中的元素。可能会诱骗nditer 这样做,但这不是它的设计目的。
    • 使用 nditer 找到了解决方案 - 通过交换轴并按顺序进行操作。
    • 感谢您的努力。确实,在这种情况下使用nditer 似乎麻烦多于其价值。不过,当我回到家时,我会尝试做一个timeit,看看我得到了什么。
    • stackoverflow.com/questions/25249380 中我偶然发现了np.ndindex,它使用了nditer。它通过在选定维度上创建 zeros 数组来完成“浅迭代”。
    【解决方案2】:

    看起来您只需将其降低一个级别。您可以使用 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])]
    

    【讨论】:

      猜你喜欢
      • 2018-07-21
      • 1970-01-01
      • 2013-05-09
      • 2013-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-19
      • 2020-08-08
      相关资源
      最近更新 更多