1. ホーム
  2. python

numpy.arrayの任意の次元に対する反復処理

2023-09-26 14:42:17

質問

numpy配列の任意の次元に対するイテレータを取得する関数はありますか?

1次元のイテレートは簡単です...。

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)みたいな名前の関数がないのが不思議です。

どのように解決するのですか?

ご提案いただいた方法は非常に高速ですが、フォームをより明確にすることで、読みやすさを向上させることができます。

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

または、より良い(より速く、より一般的で、より明示的)。

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

しかし、上記の最初のアプローチでは、約 2 倍の速度で swapaxes() のアプローチよりも約2倍遅いようです。

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