Numpy'da bir vektörün büyüklüğünü nasıl elde edersiniz?


158

"Bunu yapmanın tek bir yolu var" ile uyumlu olarak Numpy'de bir vektörün (1D dizisi) büyüklüğünü nasıl elde edersiniz?

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

Yukarıdakiler işe yarıyor, ancak böyle önemsiz ve çekirdek bir işlevi kendim belirtmem gerektiğine inanamıyorum .


1
Genellikle linalg.normaşağıda belirtildiği gibi kullanıyorum. Ama lambda şeyinizden biraz daha basit, ithalata gerek yok, sadecesum(x*x)**0.5
wim

7
Bu arada, bir isme lambda işlevi atamak için hiçbir zaman iyi bir neden yoktur.
wim

@ wim neden bu? Sadece böyle defbir işlevi bildirirken kullanmalıyım ? Bence bu meşru bir satırsa okumayı kolaylaştırır.
Nick T

6
lambda anonim bir işlev olarak tasarlanmıştır, bu yüzden ona bir isim vererek yanlış yapıyorsunuz. o zaman sadece sakat bir def versiyonu. ve eğer ısrar ederseniz, bir satıra bir def de koyabilirsiniz. lambda'yı kullanmak için haklı olabileceğiniz olağan yer, bazı argüman listesinden çağrılabilir olarak geçmek içindir. yukarıda gösterildiği gibi yanlış kullanan insanlar, guido'nun python pişmanlıkları listesine girmesinin bir nedenidir (bkz. slayt 4)
wim

6
Bağlantı öldü! Yaşasın bağlantı!
daviewales

Yanıtlar:


209

Arkanızdaki işlev numpy.linalg.norm. (Ben bir dizi - demek x.norm()- ama oh iyi bir özellik olarak temel numpy olmalıdır sanırım ).

import numpy as np
x = np.array([1,2,3,4,5])
np.linalg.norm(x)

İstediğiniz ordnnci sıra norm için isteğe bağlı olarak da besleyebilirsiniz . 1-normu istediğinizi söyleyin:

np.linalg.norm(x,ord=1)

Ve bunun gibi.


14
"Bir dizinin özelliği olmalı: x.norm ()" Tamamen katılıyorum. Genellikle numpy ile çalışırken genellikle kullandığım tüm fonksiyonlara sahip kendi Array ve Matrix alt sınıflarımı yöntem olarak kullandım. Matrix.randn([5,5])
mdaoust

3
Ayrıca, vektörlerden oluşan matrisler için, np.linalg.normşimdi axisburada tartışılan yeni bir argüman var: stackoverflow.com/a/19794741/1959808
Ioannis Filippidis 18:13

95

Hız konusunda endişeleniyorsanız, şunu kullanmalısınız:

mag = np.sqrt(x.dot(x))

İşte bazı kriterler:

>>> 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

DÜZENLEME: Gerçek hızda iyileştirme, birçok vektörün normunu almanız gerektiğinde gelir. Saf numpy işlevlerinin kullanılması döngüler için herhangi bir şey gerektirmez. Örneğin:

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
Aslında bu np.linalg.normbir darboğaz olduğunu fark ettikten sonra biraz daha az açık bir yöntem kullandım , ama sonra bir adım daha gittim ve sadece bir math.sqrt(x[0]**2 + x[1]**2)başka önemli gelişme oldu.
Nick T

@NickT, saf numpy işlevlerini kullanırken gerçek iyileştirme için düzenlememe bakın.
user545424

2
Nokta ürünün serin uygulaması!
vktec

1
numpy.linalg.normbu uygulamanın atladığı taşmaya karşı önlemler içerir. Örneğin, normunu hesaplamayı deneyin [1e200, 1e200]. Daha yavaş olmasının bir nedeni var ...
Federico Poloni

@FedericoPoloni, numpy sürümü 1.13.3 ile en azından ben almak infhesaplarken np.linalg.norm([1e200,1e200]).
user545424

16

Yine başka bir alternatif de einsumişlevi her iki dizi için numpy'de kullanmaktır :

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

veya vektörler:

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

Bununla birlikte, küçük girdilerle daha yavaş hale getirebilecek çağırma ile ilişkili bir ek yük var gibi görünüyor:

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.normbu uygulamanın atladığı taşmaya karşı önlemler içerir. Örneğin, normunu hesaplamayı deneyin [1e200, 1e200]. Daha yavaş olmasının bir nedeni var ...
Federico Poloni

7

Bulduğum en hızlı yol inner1d. Diğer numpy yöntemleriyle nasıl karşılaştırıldığı aşağıda açıklanmıştır:

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 ~ 3x daha hızlıdır. norm ve einsum daha hızlı bir saç


Aslında yukarıda yazdığınızdan linalg.normen hızlısıdır, çünkü 29ms'de 9 çağrı yapar, bu nedenle 3.222ms'de 1 çağrı ve 4.5ms'de 1 çağrı inner1d.
patapouf_ai

@bisounours_tronconneToplam yürütme süresi için zamanlamayı kullanın. Yukarıdaki kodu çalıştırırsanız, işlev çağrısı başına zamanlamanın bir dökümünü alırsınız. Hala şüpheleriniz varsa, vektör sayısını çok çok büyük bir şeye değiştirin ((10**8,3,))ve manuel olarak çalıştırın ve ardından np.linalg.norm(V,axis=1)takip np.sqrt(inner1d(V,V))edin linalg.norm
Fnord

Tamam. Açıklama için teşekkürler.
patapouf_ai

numpy.linalg.normbu uygulamanın atladığı taşmaya karşı önlemler içerir. Örneğin, normunu hesaplamayı deneyin [1e200, 1e200]. Daha yavaş olmasının bir nedeni var ...
Federico Poloni

3

fonksiyonu kullanmak norm olarak scipy.linalg (veya numpy.linalg )

>>> 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

Sen kısaca toolbelt kullanarak yapabilirsiniz vg . Numpy'nin üstünde hafif bir katmandır ve tek değerleri ve yığılmış vektörleri destekler.

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

Kütüphaneyi, son kullanımımda, bunun gibi kullanımlar tarafından motive edildiğini yarattım: NumPy'de çok ayrıntılı olan basit fikirler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.