"명확한 방법은 하나뿐"에 따라 Numpy에서 벡터 (1D 배열)의 크기를 어떻게 얻습니까?
def mag(x):
return math.sqrt(sum(i**2 for i in x))
위의 작업은 작동하지만 사소한 핵심 기능을 직접 지정해야 한다고 믿을 수는 없습니다 .
def
그런 함수를 선언 할 때만 사용해야 합니까? 합법적으로 한 줄이면 더 쉽게 읽을 수 있다고 생각합니다.
"명확한 방법은 하나뿐"에 따라 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)
또 다른 중요한 개선 사항을 사용했습니다.
numpy.linalg.norm
이 구현이 건너 뛴 오버 플로우에 대한 보호 조치가 포함되어 있습니다. 예를 들어의 표준을 계산해보십시오 [1e200, 1e200]
. 그것이 더 느린 경우 이유가 있습니다 ...
inf
컴퓨팅 할 때 얻습니다 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
에서 29ms에서 9 개의 호출을 수행하므로 3.222ms에서 1 호출에 대해 4.5ms에서 1 호출에 대해 가장 빠릅니다 inner1d
.
((10**8,3,))
한 후 수동으로 실행 np.linalg.norm(V,axis=1)
다음에 np.sqrt(inner1d(V,V))
당신이 알 수 있습니다, linalg.norm
inner1d에 비해 지상 (Lag)합니다
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
linalg.norm
아래 언급 한대로 사용 합니다. 그러나 수입품이 없어도 람다보다 약간 더 간단합니다.sum(x*x)**0.5