[python] Numpy에서 벡터의 크기를 어떻게 얻습니까?

“명확한 방법은 하나뿐”에 따라 Numpy에서 벡터 (1D 배열)의 크기를 어떻게 얻습니까?

def mag(x):
    return math.sqrt(sum(i**2 for i in x))

위의 작업은 작동하지만 사소한 핵심 기능을 직접 지정해야 한다고 믿을 수는 없습니다 .



답변

당신이 추구하는 기능은 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)

등등.


답변

속도가 걱정된다면 대신 다음을 사용해야합니다.

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


답변

또 다른 대안은 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


답변

내가 찾은 가장 빠른 방법은 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보다 빠릅니다.


답변

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에서 너무 장황한 간단한 아이디어와 같은 용도로 동기가 부여되었습니다.


답변