4

numpy コードの一部をプロファイリングすると、これら 2 つの関数内でほとんどの時間を費やしていることがわかります

numpy/matrixlib/defmatrix.py.__getitem__:301
numpy/matrixlib/defmatrix.py.__array_finalize__:279

Numpy のソースは次のとおりです。

質問1:

__getitem__のようなものを使用するたびに呼び出されるようで、整数ではなくスライスのmy_array[arg]場合はより高価になっています。arg配列スライスの呼び出しを高速化する方法はありますか?

例えば

for i in range(idx): res[i] = my_array[i:i+10].mean()

質問2:

正確にはいつ__array_finalize__呼び出され、この関数の呼び出し数を減らすことでどのようにスピードアップできますか?

ありがとう!

4

2 に答える 2

11

マトリックスをあまり使用できず、2D numpy 配列を使用するだけです。私は通常、乗算の構文を利用するために短時間だけ行列を使用します (ただし、配列に .dot メソッドを追加すると、それを行うことも少なくなることがわかります)。

しかし、あなたの質問に:

1) __getitem__defmatrix が上書き__getslice__する可能性はあるが、まだ行っていないオーバーライドを行わない限り、実際には近道はありません。整数の取得と設定用に最適化された .item および .itemset メソッドがあります (NumPy の配列スカラーではなく Python オブジェクトを返します)。

2)__array_finalize__配列オブジェクト (またはサブクラス) が作成されるたびに呼び出されます。これは、すべての配列作成が通過する C 関数から呼び出されます。 https://github.com/numpy/numpy/blob/master/numpy/core/src/multiarray/ctors.c#L1003

純粋に Python で定義されたサブクラスの場合、オーバーヘッドのある C から Python インタープリターにコールバックします。行列クラスが組み込み型 (たとえば、Cython ベースの cdef クラス) である場合、呼び出しは Python インタープリターのオーバーヘッドを回避できます。

于 2012-09-14T17:21:29.497 に答える
3

質問1:

配列スライスは、基になるデータ構造のコピー(メモリ内のデータへのポインターを保持する)を必要とする場合があるため、非常にコストがかかる可能性があります。上記の例でこれが本当にボトルネックになっている場合は、実際にiからi + 10の要素を反復処理し、手動で平均を作成することで、平均操作を実行できます。一部の操作では、これによってパフォーマンスが向上することはありませんが、新しいデータ構造の作成を回避すると、通常、プロセスが高速化されます。

もう1つの注意点として、numpy内でネイティブ型を使用していない場合、numpy配列を操作するとパフォーマンスが非常に低下します。配列にdtype=float64があり、ネイティブマシンのfloatサイズがfloat32であるとします。これにより、numpyの計算能力が大幅に向上し、全体的なパフォーマンスが低下します。これで問題がない場合もあり、データ型を維持するためにヒットすることができます。また、floatまたはintが内部として格納されるタイプが任意である場合もあります。このような場合は、dtype=float64ではなくdtype=floatを試してください。Numpyはデフォルトでネイティブタイプになっているはずです。この変更を行うことで、Numpyを多用するアルゴリズムで3倍以上のスピードアップを実現しました。

質問2:

__array_finalize__SciPyによると、「システムがobjから新しい配列を内部的に割り当てるたびに呼び出されます。ここで、objは(big)ndarrayのサブクラス(サブタイプ)です」。したがって、これは最初の質問で説明した結果です。スライスして新しい配列を作成するときは、構造コピーを作成するか、元の構造をラップして、その配列を完成させる必要があります。この操作には時間がかかります。スライスを回避すると、この操作を節約できますが、多次元データの場合、への呼び出しを完全に回避することは不可能な場合があります__array_finalize__

于 2012-09-14T17:43:37.010 に答える