web-dev-qa-db-ja.com

組み込み範囲またはnumpy.arange:どちらがより効率的ですか?

範囲式を使用して大きな配列を反復処理するとき、最高のパフォーマンスを得るには、Pythonの組み込み範囲関数、またはnumpyのarangeを使用する必要がありますか?

これまでの私の推論:

arangeはおそらくネイティブ実装に頼るため、より高速になる可能性があります。一方、arangeはメモリを占有する完全な配列を返すため、オーバーヘッドが発生する可能性があります。 Python 3の範囲式はジェネレーターであり、すべての値をメモリに保持しません。

50
clstaudt

大きな配列の場合、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配列を使用することの利点を説明しています。

58
bmu

まず、@ bmuで書かれているように、ベクトル化された計算、ufunc、およびindexingの組み合わせを使用する必要があります。実際、明示的なループが必要な場合もありますが、実際にはまれです。

python 2.6および2.7で明示的なループが必要な場合は、xrangeを使用する必要があります(以下を参照)。あなたは、Python 3、rangexrange(ジェネレーターを返します)。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よりも実装しやすくなり(読みやすくなります)、最終的にはほぼ同じ速度になります。

10
Juh_