そもそも、apply_over_axis
1D配列では配列全体が単一の引数として渡されるだけなので、この例は奇妙です。要素ごとに繰り返し呼び出されることはありません。そのためにあなたが欲しいでしょうvectorize
。
ただし、より一般的には、numpyは任意のPython関数の適用を実際に高速化することはできません。numpyの主な利点は、多くの数学関数の独自の実装を提供し、それらが高速であることです。それは魔法のように機能をとることはできず、ただ速くするだけです。
さらに、あなたの例は完全に平行ではありません。一つには、両方で同じ関数を呼び出しているわけではありません。より具体的には、テストには両方とも、時限テストで入力を作成することが含まれます。つまり、テストの時限部分を作成xrange(100)
し、その中に入れます。np.arange(100)
したがって、測定していることの一部は、xrange
オブジェクトを作成するよりもNumpy配列を作成する方が遅いということです。
>>> timeit.timeit("np.arange(100)", "import numpy as np")
0.95243776
>>> timeit.timeit("xrange(100)", "import numpy as np")
0.2129926399999995
それはおよそ5倍です。ただし、実際のアプリケーションでは、ほぼ確実に入力配列が作成されているため、これは現実的なテストではありません。
並列テストを使用すると、プレーンリストバージョンの速度は約2倍であることがわかりました。
def doNothing(crud):
return crud
>>> timeit.timeit("np.vectorize(doNothing)(thing)", "import numpy as np; from __main__ import doNothing; thing = np.arange(100)")
49.13036320000003
>>> timeit.timeit("[doNothing(x) for x in thing]", "import numpy as np; from __main__ import doNothing; thing = np.arange(100)")
25.873566400000072
さらに、適用しているのがnumpy関数である場合、numpyバージョンは大幅に高速になる可能性があります。
>>> timeit.timeit("np.log(thing)", "import numpy as np; import math; from __main__ import doNothing; thing = np.arange(100)+1")
3.2039433600000393
>>> timeit.timeit("[math.log(x) for x in thing]", "import numpy as np; import math; from __main__ import doNothing; thing = np.arange(100)+1")
37.74219519999997
物語の教訓は、numpyは実際にはNUMpyであるということです。これは数値計算を行うために作成されており、それらを高速に実行するための関数を備えています。すべてのループを高速化するだけではありません。任意の関数を適用しているオブジェクトの大きな配列がある場合、numpyがコードを高速化する可能性は低く、速度を低下させる可能性さえあります。(多次元配列への複雑なインデックス付けなどの機能が便利で、ネストされたリストなどを使用する同等のPython構造よりも高速である可能性があるため、数値以外のデータにも非常に役立ちます。ループの高速化には役立ちません。これらの構造。)