6

numpy ufuncと組み込み演算子と組み込み演算子の「関数」バージョンを使用する利点とトレードオフに興味があります。

私はすべてのufuncに興味があります。たぶん、あるものは他のものよりも役に立つ時があります。ただし、<簡単にするために例に使用します。

numpy 配列を単一の数値で「フィルタリング」してブール配列を取得する方法はいくつかあります。どの形式でも同じ結果が得られますが、いずれかを使用するのに適した時間/場所はありますか? この例では、配列を単一の数値と比較しているため、3 つすべてが機能します。

次の配列を使用したすべての例を検討してください。

>>> x = numpy.arange(0, 10000)
>>> x
array([   0,    1,    2, ..., 9997, 9998, 9999])

「<」演算子

>>> x < 5000
array([ True,  True,  True, ..., False, False, False], dtype=bool)
>>> %timeit x < 5000
100000 loops, best of 3: 15.3 us per loop

operator.lt

>>> import operator
>>> operator.lt(x, 5000)
array([ True,  True,  True, ..., False, False, False], dtype=bool)
>>> %timeit operator.lt(x, 5000)
100000 loops, best of 3: 15.3 us per loop

numpy.less

>>> numpy.less(x, 5000)
array([ True,  True,  True, ..., False, False, False], dtype=bool)
>>> %timeit numpy.less(x, 5000)
100000 loops, best of 3: 15 us per loop

それらはすべて、ほぼ同等のパフォーマンスとまったく同じ結果を達成することに注意してください。とにかく、これらの呼び出しはすべて実際には同じ関数で終わると推測しています。<どちらもnumpy配列にoperator.ltマップされているため、おそらくまたは同等のものを使用して実装されていますか?__lt__numpy.less

では、どちらがより「慣用的」で「好ましい」のでしょうか?

4

2 に答える 2

3

この場合、推奨される形式はx < 5000、より単純であり、既に numpy 配列を使用しているためです。

ufuncs は、これらの操作を任意のタイプのデータに対して実行できるようにすることを目的としています (numpy 配列だけでなく)

>>> numpy.less([1, 2, 3, 4, 6, 8], 5)
array([ True,  True,  True,  True, False, False], dtype=bool)

>>> [1, 2, 3, 4, 6, 8] < 5
False

Python 3 では、この最後の比較でエラーが発生します。

于 2013-03-28T18:20:40.547 に答える
3

一般的に言えば、「可読性が重要」というマントラを考えると、常に実際のオペレーターを選択する必要があります。バージョンの使用には、よりコンパクトなにoperator置き換えることができる場所がありますが、それ以外はあまりありません。また、パラメーターを使用して計算された値を既存の配列に直接格納する場合を除き、対応する ufunc への明示的な呼び出しを使用するべきではありません。lambda a, b: a < boperator.ltout

そうは言っても、あなたが心配しているのがパフォーマンスである場合は、公平な比較を行う必要があります。なぜなら、あなたが言うように、すべての呼び出しは最終的に numpy のlessufunc によって処理されるからです。

データがすでに numpy 配列にある場合は、それらがすべて同様に実行されていることをすでに示しているため<、明確にするために演算子を使用してください。

データが python オブジェクト、たとえばリストにある場合はどうなりますか? さて、ここにあなたが熟考するためのいくつかのタイミングがあります:

In [13]: x = range(10**5)

In [19]: %timeit [j < 5000 for j in x]
100 loops, best of 3: 5.32 ms per loop

In [20]: %timeit np.less(x, 5000)
100 loops, best of 3: 11.3 ms per loop

In [21]: %timeit [operator.lt(j, 5000) for j in x]
100 loops, best of 3: 16.2 ms per loop

なぜoperator.ltそんなに遅いのかはわかりませんが、明らかに近づきたくないでしょう。Python オブジェクト入力からの出力として numpy 配列を取得する場合は、おそらくこれが最も高速です。

In [22]: %timeit np.fromiter((j < 5000 for j in x), dtype=bool, count=10**5)
100 loops, best of 3: 7.91 ms per loop

numpy 配列で動作する ufuncは、上記のいずれよりもはるかに高速であることに注意してください。

In [24]: y = np.array(x)

In [25]: %timeit y < 5000
10000 loops, best of 3: 82.8 us per loop
于 2013-03-28T18:54:00.600 に答える