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


157

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

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

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


1
나는 일반적으로 linalg.norm아래 언급 한대로 사용 합니다. 그러나 수입품이 없어도 람다보다 약간 더 간단합니다.sum(x*x)**0.5
wim

7
그건 그렇고, 람다 함수를 이름에 할당해야 할 이유가 없습니다.
wim

@wim 왜 그렇습니까? def그런 함수를 선언 할 때만 사용해야 합니까? 합법적으로 한 줄이면 더 쉽게 읽을 수 있다고 생각합니다.
Nick T

6
람다는 익명의 기능을 목적으로하므로 잘못하고있는 이름을 부여합니다. 그것은 단지 데프의 절름발이 버전입니다. 그리고 당신이 주장한다면, 당신은 또한 한 줄에 데프를 넣을 수 있습니다. 람다를 사용하는 것이 정당한 일반적인 장소는 일부 인수 목록을 호출 가능 항목으로 전달하는 것입니다. 위와 같이 사람들이 그것을 잘못 사용하는 것은 그것이 guido의 파이썬 후회 목록에 올라간 이유 중 하나입니다 (슬라이드 4 참조)
wim

6
링크가 죽었다! 링크를 오래 산다!
daviewales

답변:


209

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

등등.


14
"배열의 속성이어야합니다 : x.norm ()"전적으로 동의합니다. 일반적으로 numpy로 작업 할 때 일반적으로 사용하는 모든 함수가있는 자체 Array 및 Matrix 하위 클래스를 메소드로 사용합니다. Matrix.randn([5,5])
mdaoust

3
또한, 벡터로 구성된 행렬을 위해, np.linalg.norm이제 새로운있다 axis: 여기서 논의 인수, stackoverflow.com/a/19794741/1959808
요안 Filippidis

95

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

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

1
실제로 np.linalg.norm병목 현상 을 발견 한 후 약간 덜 명시 적 인 방법을 사용 했지만 한 단계 더 나아가서 math.sqrt(x[0]**2 + x[1]**2)또 다른 중요한 개선 사항을 사용했습니다.
Nick T

@ NickT, 순수한 numpy 함수를 사용할 때 실제 개선 사항에 대한 편집 내용을 참조하십시오.
user545424

2
내적 제품의 멋진 응용 프로그램!
vktec

1
numpy.linalg.norm이 구현이 건너 뛴 오버 플로우에 대한 보호 조치가 포함되어 있습니다. 예를 들어의 표준을 계산해보십시오 [1e200, 1e200]. 그것이 더 느린 경우 이유가 있습니다 ...
Federico Poloni

@FedericoPoloni, 적어도 numpy 버전 1.13.3에서는 inf컴퓨팅 할 때 얻습니다 np.linalg.norm([1e200,1e200]).
user545424

16

또 다른 대안은 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]. 그것이 더 느린 경우 이유가 있습니다 ...
Federico Poloni

7

내가 찾은 가장 빠른 방법은 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.
patapouf_ai 2016 년

@bisounours_tron 총 실행 시간에 대한 타이밍을 고려하십시오. 위의 코드를 실행하면 함수 호출 당 타이밍이 분류됩니다. 당신은 여전히 의심이있는 경우처럼, 아주 아주 큰 무언가에 벡터 수를 변경 ((10**8,3,))한 후 수동으로 실행 np.linalg.norm(V,axis=1)다음에 np.sqrt(inner1d(V,V))당신이 알 수 있습니다, linalg.norminner1d에 비해 지상 (Lag)합니다
Fnord

확인. 명확하게 해 주셔서 감사합니다.
patapouf_ai

numpy.linalg.norm이 구현이 건너 뛴 오버 플로우에 대한 보호 조치가 포함되어 있습니다. 예를 들어의 표준을 계산해보십시오 [1e200, 1e200]. 그것이 더 느린 경우 이유가 있습니다 ...
Federico Poloni

3

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

1

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.