“명확한 방법은 하나뿐”에 따라 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에서 너무 장황한 간단한 아이디어와 같은 용도로 동기가 부여되었습니다.