範囲式を使用して大きな配列を反復処理するとき、最高のパフォーマンスを得るには、Pythonの組み込み範囲関数、またはnumpyのarange
を使用する必要がありますか?
これまでの私の推論:
arange
はおそらくネイティブ実装に頼るため、より高速になる可能性があります。一方、arange
はメモリを占有する完全な配列を返すため、オーバーヘッドが発生する可能性があります。 Python 3の範囲式はジェネレーターであり、すべての値をメモリに保持しません。
大きな配列の場合、numpyがより高速なソリューションになるはずです。
Numpyでは、ベクトル化計算 funcs および indexing の組み合わせを使用して、C
速度で実行される問題を解決する必要があります。 numpy配列のループはこれに比べて非効率的です。
(あなたができる最悪のことのようなものは、あなたの質問の最初の文が示唆するように、range
またはnp.arange
で作成されたインデックスで配列を反復することですが、あなたが本当にそれを意味します。)
import numpy as np
import sys
sys.version
# out: '2.7.3rc2 (default, Mar 22 2012, 04:35:15) \n[GCC 4.6.3]'
np.version.version
# out: '1.6.2'
size = int(1E6)
%timeit for x in range(size): x ** 2
# out: 10 loops, best of 3: 136 ms per loop
%timeit for x in xrange(size): x ** 2
# out: 10 loops, best of 3: 88.9 ms per loop
# avoid this
%timeit for x in np.arange(size): x ** 2
#out: 1 loops, best of 3: 1.16 s per loop
# use this
%timeit np.arange(size) ** 2
#out: 100 loops, best of 3: 19.5 ms per loop
したがって、この場合、numpyはxrange
を使用するよりも4倍高速です。問題に応じて、numpyは4倍または5倍の速度よりもはるかに高速です。
この質問 に対する回答は、python大規模なデータセットのリストの代わりにnumpy配列を使用することの利点を説明しています。
まず、@ bmuで書かれているように、ベクトル化された計算、ufunc、およびindexingの組み合わせを使用する必要があります。実際、明示的なループが必要な場合もありますが、実際にはまれです。
python 2.6および2.7で明示的なループが必要な場合は、xrangeを使用する必要があります(以下を参照)。あなたは、Python 3、rangeはxrange(ジェネレーターを返します)。rangeがあなたにとって良いかもしれません。
今、あなたはそれを自分で試してみるべきです(timeitを使用:-ここではipython "magic function"):
%timeit for i in range(1000000): pass
[out] 10 loops, best of 3: 63.6 ms per loop
%timeit for i in np.arange(1000000): pass
[out] 10 loops, best of 3: 158 ms per loop
%timeit for i in xrange(1000000): pass
[out] 10 loops, best of 3: 23.4 ms per loop
繰り返しますが、上記のように、ほとんどの場合、Cの速度を実行するnumpyベクトル/配列式(またはufuncなど)を使用することができます:はるかに速い。これが「ベクトルプログラミング」と呼ばれるものです。これにより、プログラムはCよりも実装しやすくなり(読みやすくなります)、最終的にはほぼ同じ速度になります。