「それを行うには明らかな方法が1つしかない」に合わせて、Numpyでベクトル(1D配列)の大きさをどのように取得しますか?
def mag(x):
return math.sqrt(sum(i**2 for i in x))
上記は機能しますが、私はそのような些細なコア機能を自分で指定しなければならないとは信じられません。
def
そのような関数を宣言するときにのみ使用する必要がありますか?正当に一行だと読みやすくなると思います。
「それを行うには明らかな方法が1つしかない」に合わせて、Numpyでベクトル(1D配列)の大きさをどのように取得しますか?
def mag(x):
return math.sqrt(sum(i**2 for i in x))
上記は機能しますが、私はそのような些細なコア機能を自分で指定しなければならないとは信じられません。
def
そのような関数を宣言するときにのみ使用する必要がありますか?正当に一行だと読みやすくなると思います。
回答:
あなたが求めている関数はですnumpy.linalg.norm
。(私はそれが配列のプロパティとして基本のnumpyにあるべきだと思います-言うx.norm()
-しかしまあ)
import numpy as np
x = np.array([1,2,3,4,5])
np.linalg.norm(x)
必要なord
n次のノルムのオプションでフィードすることもできます。1ノルムが必要だとします。
np.linalg.norm(x,ord=1)
等々。
Matrix.randn([5,5])
速度が心配な場合は、代わりに次を使用してください。
mag = np.sqrt(x.dot(x))
ここにいくつかのベンチマークがあります:
>>> import timeit
>>> timeit.timeit('np.linalg.norm(x)', setup='import numpy as np; x = np.arange(100)', number=1000)
0.0450878
>>> timeit.timeit('np.sqrt(x.dot(x))', setup='import numpy as np; x = np.arange(100)', number=1000)
0.0181372
編集:実際の速度の向上は、多くのベクトルの規範をとらなければならないときに起こります。純粋なnumpy関数を使用するためにforループは必要ありません。例えば:
In [1]: import numpy as np
In [2]: a = np.arange(1200.0).reshape((-1,3))
In [3]: %timeit [np.linalg.norm(x) for x in a]
100 loops, best of 3: 4.23 ms per loop
In [4]: %timeit np.sqrt((a*a).sum(axis=1))
100000 loops, best of 3: 18.9 us per loop
In [5]: np.allclose([np.linalg.norm(x) for x in a],np.sqrt((a*a).sum(axis=1)))
Out[5]: True
np.linalg.norm
がボトルネックであることを発見した後、私は実際にこのわずかに明白でない方法を使用しましたが、それから私はさらに一歩進んで、math.sqrt(x[0]**2 + x[1]**2)
もう1つの重要な改善であるだけを使用しました。
numpy.linalg.norm
この実装がスキップするオーバーフローに対する保護機能が含まれています。たとえば、のノルムを計算してみてください[1e200, 1e200]
。遅くなるのには理由があります...
inf
計算時に取得するnumpyバージョン1.13.3ではnp.linalg.norm([1e200,1e200])
。
さらに別の選択肢はeinsum
、いずれかの配列に対してnumpyで関数を使用することです:
In [1]: import numpy as np
In [2]: a = np.arange(1200.0).reshape((-1,3))
In [3]: %timeit [np.linalg.norm(x) for x in a]
100 loops, best of 3: 3.86 ms per loop
In [4]: %timeit np.sqrt((a*a).sum(axis=1))
100000 loops, best of 3: 15.6 µs per loop
In [5]: %timeit np.sqrt(np.einsum('ij,ij->i',a,a))
100000 loops, best of 3: 8.71 µs per loop
またはベクトル:
In [5]: a = np.arange(100000)
In [6]: %timeit np.sqrt(a.dot(a))
10000 loops, best of 3: 80.8 µs per loop
In [7]: %timeit np.sqrt(np.einsum('i,i', a, a))
10000 loops, best of 3: 60.6 µs per loop
ただし、小さな入力では遅くなる可能性がある、呼び出しに関連するオーバーヘッドがいくつかあるようです。
In [2]: a = np.arange(100)
In [3]: %timeit np.sqrt(a.dot(a))
100000 loops, best of 3: 3.73 µs per loop
In [4]: %timeit np.sqrt(np.einsum('i,i', a, a))
100000 loops, best of 3: 4.68 µs per loop
numpy.linalg.norm
この実装がスキップするオーバーフローに対する保護機能が含まれています。たとえば、のノルムを計算してみてください[1e200, 1e200]
。遅くなるのには理由があります...
私が見つけた最速の方法はinner1d経由です。他のnumpyメソッドと比較する方法は次のとおりです。
import numpy as np
from numpy.core.umath_tests import inner1d
V = np.random.random_sample((10**6,3,)) # 1 million vectors
A = np.sqrt(np.einsum('...i,...i', V, V))
B = np.linalg.norm(V,axis=1)
C = np.sqrt((V ** 2).sum(-1))
D = np.sqrt((V*V).sum(axis=1))
E = np.sqrt(inner1d(V,V))
print [np.allclose(E,x) for x in [A,B,C,D]] # [True, True, True, True]
import cProfile
cProfile.run("np.sqrt(np.einsum('...i,...i', V, V))") # 3 function calls in 0.013 seconds
cProfile.run('np.linalg.norm(V,axis=1)') # 9 function calls in 0.029 seconds
cProfile.run('np.sqrt((V ** 2).sum(-1))') # 5 function calls in 0.028 seconds
cProfile.run('np.sqrt((V*V).sum(axis=1))') # 5 function calls in 0.027 seconds
cProfile.run('np.sqrt(inner1d(V,V))') # 2 function calls in 0.009 seconds
inner1dは、linalg.normより3倍高速で、髪はeinsumより高速です
linalg.norm
からすると、29ミリ秒で9回の呼び出しを行うため、3.222ミリ秒で1回の呼び出しを行うのに対し、4.5msで1回の呼び出しを行うので、最速ですinner1d
。
((10**8,3,))
、その後、手動で実行np.linalg.norm(V,axis=1)
に続いてnp.sqrt(inner1d(V,V))
、あなたはわかりますlinalg.norm
inner1dに比べて遅れる
numpy.linalg.norm
この実装がスキップするオーバーフローに対する保護機能が含まれています。たとえば、のノルムを計算してみてください[1e200, 1e200]
。遅くなるのには理由があります...
scipy.linalg(またはnumpy.linalg)で関数normを使用します
>>> from scipy import linalg as LA
>>> a = 10*NP.random.randn(6)
>>> a
array([ 9.62141594, 1.29279592, 4.80091404, -2.93714318,
17.06608678, -11.34617065])
>>> LA.norm(a)
23.36461979210312
>>> # compare with OP's function:
>>> import math
>>> mag = lambda x : math.sqrt(sum(i**2 for i in x))
>>> mag(a)
23.36461979210312
これは、toolbelt vgを使用して簡潔に行うことができます。それはnumpyの上にある軽いレイヤーであり、単一の値とスタックされたベクトルをサポートします。
import numpy as np
import vg
x = np.array([1, 2, 3, 4, 5])
mag1 = np.linalg.norm(x)
mag2 = vg.magnitude(x)
print mag1 == mag2
# True
私は最後のスタートアップでライブラリを作成しました。そこでは、このような使用法によって動機付けられました:NumPyで非常に冗長すぎる単純なアイデア。
linalg.norm
以下のように使用しています。しかし、不要輸入して、ちょうどあなたのラムダのものよりも少し簡単ですsum(x*x)**0.5