En accord avec le "Il n'y a qu'un seul moyen évident de le faire", comment obtenez-vous la magnitude d'un vecteur (tableau 1D) dans Numpy?
def mag(x):
return math.sqrt(sum(i**2 for i in x))
Ce qui précède fonctionne, mais je ne peux pas croire que je dois spécifier moi-même une fonction aussi triviale et essentielle.
La fonction que vous recherchez est numpy.linalg.norm
. (Je pense que cela devrait être dans numpy de base en tant que propriété d'un tableau - disons x.norm()
- mais bon).
import numpy as np
x = np.array([1,2,3,4,5])
np.linalg.norm(x)
Vous pouvez également insérer une variable ord
facultative pour la norme de nième ordre souhaitée. Dites que vous vouliez la norme 1:
np.linalg.norm(x,ord=1)
Etc.
Si vous êtes inquiet à propos de la vitesse, utilisez plutôt:
mag = np.sqrt(x.dot(x))
Voici quelques repères:
>>> 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
EDIT: L'amélioration réelle de la vitesse survient lorsque vous devez prendre la norme de nombreux vecteurs. L'utilisation de fonctions numpy pures ne nécessite aucune boucle for. Par exemple:
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
Une autre alternative consiste à utiliser la fonction einsum
dans numpy pour les deux tableaux:
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
ou vecteurs:
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
Il semble toutefois qu'il y ait des frais généraux associés à l'appel qui peuvent le ralentir avec de petites entrées:
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
Le moyen le plus rapide que j'ai trouvé est via inner1d. Voici comment cela se compare à d'autres méthodes 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 est ~ 3x plus rapide que linalg.norm et un cheveu plus rapide que einsum
utilisez la fonctionnormin scipy.linalg (ou 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
Vous pouvez le faire de manière concise en utilisant toolbelt vg . C'est une couche légère au-dessus de numpy et elle supporte les valeurs uniques et les vecteurs empilés.
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
J'ai créé la bibliothèque lors de mon dernier démarrage, où elle était motivée par des utilisations telles que celle-ci: des idées simples et trop verbeuses dans NumPy.