78

是否有函数可以在 numpy 数组的任意维度上获取迭代器?

迭代第一个维度很容易......

In [63]: c = numpy.arange(24).reshape(2,3,4)

In [64]: for r in c :
   ....:     print r
   ....: 
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[[12 13 14 15]
 [16 17 18 19]
 [20 21 22 23]]

但迭代其他维度更难。例如,最后一个维度:

In [73]: for r in c.swapaxes(2,0).swapaxes(1,2) :
   ....:     print r
   ....: 
[[ 0  4  8]
 [12 16 20]]
[[ 1  5  9]
 [13 17 21]]
[[ 2  6 10]
 [14 18 22]]
[[ 3  7 11]
 [15 19 23]]

我正在制作一个生成器来自己执行此操作,但我很惊讶没有一个名为 numpy.ndarray.iterdim(axis=0) 的函数可以自动执行此操作。

4

6 回答 6

66

您提出的建议相当快,但可以通过更清晰的形式提高易读性:

for i in range(c.shape[-1]):
    print c[:,:,i]

或者,更好(更快、更通用、更明确):

for i in range(c.shape[-1]):
    print c[...,i]

但是,上面的第一种方法似乎比该方法慢两倍swapaxes()

python -m timeit -s 'import numpy; c = numpy.arange(24).reshape(2,3,4)' \
    'for r in c.swapaxes(2,0).swapaxes(1,2): u = r'
100000 loops, best of 3: 3.69 usec per loop

python -m timeit -s 'import numpy; c = numpy.arange(24).reshape(2,3,4)' \
    'for i in range(c.shape[-1]): u = c[:,:,i]'
100000 loops, best of 3: 6.08 usec per loop

python -m timeit -s 'import numpy; c = numpy.arange(24).reshape(2,3,4)' \
    'for r in numpy.rollaxis(c, 2): u = r'
100000 loops, best of 3: 6.46 usec per loop

我猜这是因为swapaxes()不复制任何数据,并且因为处理c[:,:,i] 可能是通过通用代码完成的(处理:被更复杂的切片替换的情况)。

但是请注意,更明确的第二种解决方案c[...,i]既清晰又快速:

python -m timeit -s 'import numpy; c = numpy.arange(24).reshape(2,3,4)' \
    'for i in range(c.shape[-1]): u = c[...,i]'
100000 loops, best of 3: 4.74 usec per loop
于 2009-10-20T08:13:50.370 回答
31

我会使用以下内容:

c = numpy.arange(2 * 3 * 4)
c.shape = (2, 3, 4)

for r in numpy.rollaxis(c, 2):
    print(r)

函数rollaxis在数组上创建一个新视图。在这种情况下,它是将轴 2 移动到前面,相当于操作c.transpose(2, 0, 1)

于 2011-05-07T19:05:11.647 回答
8

因此,正如您所展示的,人们可以轻松地迭代第一个维度。对任意维度执行此操作的另一种方法是使用 numpy.rollaxis() 将给定维度带到第一个维度(默认行为),然后使用返回的数组(这是一个视图,所以这很快)作为迭代器.

In [1]: array = numpy.arange(24).reshape(2,3,4)

In [2]: for array_slice in np.rollaxis(array, 1):
   ....:     print array_slice.shape
   ....:
(2, 4)
(2, 4)
(2, 4)

编辑:我会评论说我向 numpy 提交了一个 PR 来解决这个问题: https ://github.com/numpy/numpy/pull/3262 。共识是这还不足以添加到 numpy 代码库中。我认为使用 np.rollaxis 是最好的方法,如果你想要一个交互器,请将它包装在 iter() 中。

于 2013-04-18T14:07:13.187 回答
5

估计没有功能。当我编写函数时,我最终采用了 EOL 也建议的迭代。对于未来的读者,这里是:

def iterdim(a, axis=0) :
  a = numpy.asarray(a);
  leading_indices = (slice(None),)*axis
  for i in xrange(a.shape[axis]) :
    yield a[leading_indices+(i,)]
于 2009-10-20T14:10:18.487 回答
3

您可以使用 numpy.shape 获取尺寸,然后使用 range 对其进行迭代。

n0, n1, n2 = numpy.shape(c)

for r in range(n0):
    print(c[r,:,:])
于 2019-08-08T16:39:13.383 回答
1

以下正是您正在寻找的内容:

for x in np.moveaxis(X, axis, 0):
于 2021-06-14T20:41:54.593 回答