Numpy配列を「直接」反復することと、tolist
メソッドを介して反復することの間に有意義な違いがあることに気付きました。以下のタイミングを参照してください。
直接[i for i in np.arange(10000000)]
via tolist
[i for i in np.arange(10000000).tolist()]
もっと速くする方法を見つけたので。他に何がそれを速くすることができるのかを尋ねたかったのですか?
numpy配列を反復する最も速い方法は何ですか?
これらは遅いマシンでの私のタイミングです
_In [1034]: timeit [i for i in np.arange(10000000)]
1 loop, best of 3: 2.16 s per loop
_
範囲を直接生成する場合(Py3なので、これはジェネレーターです)、時間ははるかに優れています。このサイズのリストを理解するためのベースラインとしてください。
_In [1035]: timeit [i for i in range(10000000)]
1 loop, best of 3: 1.26 s per loop
_
tolist
は最初にarangeをリストに変換します。少し時間がかかりますが、繰り返しはまだリストにあります
_In [1036]: timeit [i for i in np.arange(10000000).tolist()]
1 loop, best of 3: 1.6 s per loop
_
list()
の使用-配列の直接反復と同じ時間。これは、直接反復が最初にこれを行うことを示唆しています。
_In [1037]: timeit [i for i in list(np.arange(10000000))]
1 loop, best of 3: 2.18 s per loop
In [1038]: timeit np.arange(10000000).tolist()
1 loop, best of 3: 927 ms per loop
_
.tolistでの繰り返し
_In [1039]: timeit list(np.arange(10000000))
1 loop, best of 3: 1.55 s per loop
_
一般に、ループする必要がある場合は、リストでの作業の方が高速です。リストの要素へのアクセスはより簡単です。
インデックスによって返された要素を見てください。
_a[0]
_は別のnumpy
オブジェクトです。 a
の値から構成されますが、単にフェッチされた値ではありません
list(a)[0]
は同じタイプです。リストは単に_[a[0], a[1], a[2]]]
_です
_In [1043]: a = np.arange(3)
In [1044]: type(a[0])
Out[1044]: numpy.int32
In [1045]: ll=list(a)
In [1046]: type(ll[0])
Out[1046]: numpy.int32
_
しかしtolist
は配列を純粋なリストに変換します。この場合は、intのリストです。 list()
よりも多くの機能を果たしますが、コンパイルされたコードでは機能します。
_In [1047]: ll=a.tolist()
In [1048]: type(ll[0])
Out[1048]: int
_
一般に、list(anarray)
は使用しないでください。それはめったに役立つことはほとんどなく、tolist()
ほど強力ではありません。
配列を反復する最も速い方法は何ですか-なし。少なくともPythonではありません。 Cコードでは高速な方法があります。
a.tolist()
は、配列から整数のリストを作成する最も高速なベクトル化された方法です。繰り返しますが、コンパイルされたコードでは繰り返します。
しかし、あなたの本当の目標は何ですか?
これは実際には驚くべきことではありません。最も遅いものから始めて、メソッドを1つずつ調べてみましょう。
_[i for i in np.arange(10000000)]
_
このメソッドは、python numpy配列(Cメモリスコープに格納されている)に一度に1要素ずつ到達するように要求し、Pythonオブジェクトをメモリに割り当てます。リスト内のそのオブジェクトへのポインタを作成します。Cバックエンドに格納されているnumpy配列間をパイプして純粋なpythonにプルするたびに、オーバーヘッドコストが発生します。この方法では、そのコストが10,000,000回追加されます。
次:
_[i for i in np.arange(10000000).tolist()]
_
この場合、.tolist()
を使用すると、numpy Cバックエンドが1回呼び出され、すべての要素が一度にリストに割り当てられます。次に、pythonを使用してそのリストを反復処理します。
最後に:
_list(np.arange(10000000))
_
これは基本的に上記と同じことを行いますが、numpyのネイティブタイプオブジェクトのリストを作成します(例:_np.int64
_)。 list(np.arange(10000000))
とnp.arange(10000000).tolist()
の使用は、ほぼ同時に行う必要があります。
したがって、反復に関しては、numpy
を使用する主な利点は、反復する必要がないことです。操作は、ベクトル化された方法でアレイに適用されます。反復は単にそれを遅くします。配列要素を繰り返し処理していることに気付いた場合は、試行錯誤しているアルゴリズムを再構築する方法を探す必要があります。これは、数の多い操作のみを使用する方法(組み込みが多すぎる)であるか、本当に必要な場合は、 _np.apply_along_axis
_、_np.apply_over_axis
_、または_np.vectorize
_を使用します。
テストケースにnumpy array
[[ 34 107]
[ 963 144]
[ 921 1187]
[ 0 1149]]
range
とenumerate
を使用してこれを1回だけ実行します
使用範囲
loopTimer1 = default_timer()
for l1 in range(0,4):
print(box[l1])
print("Time taken by range: ",default_timer()-loopTimer1)
結果
[ 34 107]
[963 144]
[ 921 1187]
[ 0 1149]
Time taken by range: 0.0005405639985838206
列挙を使用
loopTimer2 = default_timer()
for l2,v2 in enumerate(box):
print(box[l2])
print("Time taken by enumerate: ", default_timer() - loopTimer2)
結果
[ 34 107]
[963 144]
[ 921 1187]
[ 0 1149]
Time taken by enumerate: 0.00025605700102460105
私が選んだこのテストケースenumerate
はより速く動作します