6

整数の 2 次元配列ですべての項目を反復処理し、値を変更する必要があります (何らかの規則に従って、重要ではありません)。

Python ランタイムと C# または Java ランタイムのパフォーマンスに大きな違いがあることに驚きました。完全に間違った python コード (v2.7.2) を書きましたか?

import numpy
a = numpy.ndarray((5000,5000), dtype = numpy.int32)
for x in numpy.nditer(a.T):
    x = 123
>python -m timeit -n 2 -r 2 -s "import numpy; a = numpy.ndarray((5000,5000), dtype=numpy.int32)" "for x in numpy.nditer(a.T):" "  x = 123"
2 loops, best of 2: 4.34 sec per loop

たとえば、C# コードは 50 ミリ秒しか実行しません。つまり、python はほぼ100 倍遅くなりますmatrix(変数はすでに初期化されていると仮定します)

for (y = 0; y < 5000; y++)
for (x = 0; x < 5000; x++)
    matrix[y][x] = 123;
4

6 に答える 6

13

うん!Python で numpy 配列を反復処理するのは遅いです。(同様に、Python リストを繰り返し処理するよりも遅くなります。)

通常、それらを直接反復することは避けます。

変更の基準となるルールの例を挙げていただければ、簡単にベクトル化できる可能性が高くなります。

おもちゃの例として:

import numpy as np

x = np.linspace(0, 8*np.pi, 100)
y = np.cos(x)

x[y > 0] = 100

ただし、多くの場合、アルゴリズム (有限差分法など) が原因で、または一時配列のメモリ コストを削減するために反復する必要があります。

その場合は、CythonWeave、または類似のものを見てください。

于 2012-04-11T19:45:07.840 に答える
10

あなたが与えた例は、おそらく2次元のNumPy配列のすべての項目を123に設定することを意図していました.これは、次のように効率的に行うことができます:

a.fill(123)

また

a[:] = 123
于 2012-04-11T19:50:31.560 に答える
5

Python は、C や C# よりもはるかに動的な言語です。ループが非常に遅い主な理由は、すべてのパスで、CPython インタープリターが時間を浪費する余分な作業を行っているためです。具体的には、名前xをイテレーターからの次のオブジェクトにバインドし、割り当てを評価するときにもう一度名前を調べますx

@Sven Marnachが指摘したように、メソッド関数numpy.fill()を呼び出すことができ、高速です。その関数はコンパイルされた C またはおそらく Fortran であり、numpy.arrayデータ構造のアドレスを単純にループして値を入力します。Python よりもはるかに動的でないため、この単純なケースに適しています。

しかし、ここで PyPy を考えてみましょう。プログラムを PyPy で実行すると、JIT はコードが実際に行っていることを分析します。この例では、名前xは代入以外には使用されず、名前のバインドを最適化して取り除くことができることに注意してください。この例は、PyPy が大幅に高速化するものです。PyPy は普通の Python よりも 10 倍高速になる可能性があります (つまり、C の 100 分の 1 ではなく、10 分の 1 の速さです)。

http://pypy.org

私が理解しているように、PyPy はまだしばらく Numpy で動作しないため、既存の Numpy コードを PyPy で実行することはまだできません。しかし、その日は来ています。

私は PyPy に興奮しています。非常に高水準の言語 (Python) で記述しながら、「ポータブル アセンブリ言語」(C) で記述した場合とほぼ同等のパフォーマンスが得られるという希望を与えてくれます。このような例では、Numpy は、CPU からの SIMD 命令 (SSE2、NEON など) を使用することで、単純な C コードのパフォーマンスを上回ることさえあります。この例では、SIMD を使用して、ループごとに 4 つの整数を 123 に設定でき、単純な C ループよりも高速になります。(C コンパイラーが SIMD 最適化も使用していない限り! 考えてみれば、これはこのケースの可能性が高いです。したがって、この例では高速ではなく、「ほぼ C の速度」に戻ります。しかし、よりトリッキーなケースを想像することができます。 C コンパイラは、将来の PyPy が最適化するほどスマートではありません。)

しかし、今のところ PyPy は気にしないでください。Numpy を使用する場合は、numpy.fill()コードを高速化するために、そのような関数をすべて学習することをお勧めします。

于 2012-04-11T21:37:39.277 に答える
4

C++ では、プログラマーの時間よりもマシンの時間が重視されます。

Python は、マシン時間よりもプログラマー時間を重視します。

Pypy は python で書かれた python であり、numpy の始まりがあります。あなたはそれを試すかもしれません。Pypy には優れた JIT があり、処理が非常に高速になります。

Python の方言を C に変換し、C を Python C 拡張モジュールにコンパイルできる cython を試すこともできます。これにより、ほとんどのコードで引き続き CPython を使用できますが、それでも少し高速化されます。ただし、Pypy と Cython を比較してみた 1 つのマイクロベンチマークでは、Pypy は Cython よりもかなり高速でした。

Cython は非常に pythonish な構文を使用しますが、Python のデータ型と C のデータ型をかなり自由に混在させることができます。ホットスポットを C データ型でやり直すと、かなり高速になるはずです。Python のデータ型を使い続けると、Cython によっても高速化されますが、それほどではありません。

于 2012-04-11T23:00:54.290 に答える
0

コードはのnditer要素に値を割り当てませんa。これはタイミングの問題には影響しませんが、nditer.

正しいバージョンは次のとおりです。

for i in np.nditer(a, op_flags=[["readwrite"]]):
    i[...] = 123

[...]、 shape の配列である loop 値への参照を保持するために必要です()

A.T変更されるベースの値であるため、を使用しても意味がありませんA

この割り当てを行う適切な方法は であることに同意しますa[:]=123

于 2014-08-03T19:49:35.527 に答える