Hoe kom je aan de grootte van een vector in Numpy?

In overeenstemming met de “Er is maar één voor de hand liggende manier om het te doen”, hoe krijg je de grootte van een vector (1D-array) in Numpy?

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

Het bovenstaande werkt, maar ik kan niet gelovendat ik zelf zo’n triviale en kernfunctie moet specificeren.


Antwoord 1, autoriteit 100%

De functie die u zoekt is numpy.linalg.norm. (Ik denk dat het in base numpy zou moeten staan als een eigenschap van een array — zeg x.norm()— maar goed).

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

Je kunt ook een optionele ordinvoeren voor de n-de-orde-norm die je wilt. Stel dat je de 1-norm wilde:

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

Enzovoort.


Antwoord 2, autoriteit 41%

Als je je zorgen maakt over snelheid, gebruik dan:

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

Hier zijn enkele benchmarks:

>>> 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: De echte snelheidsverbetering komt wanneer je de norm van veel vectoren moet nemen. Het gebruik van pure numpy-functies vereist geen for-lussen. Bijvoorbeeld:

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

Antwoord 3, Autoriteit 6%

Nog een ander alternatief is om de einsum-functie in Numpy voor beide arrays te gebruiken:

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

of vectoren:

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

Er lijken echter wat overhead te zijn die geassocieerd is om het te bellen die het langzamer kan maken met kleine inputs:

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

Antwoord 4, Autoriteit 3%

Snelste manier die ik vond is via inner1d. Dit is hoe het vergelijkt met andere numpy-methoden:

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 is ~3x sneller dan linalg.norm en een haar sneller dan einsum


Antwoord 5

gebruik de functie normin scipy.linalg(of 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

Antwoord 6

Je kunt dit beknopt doen met behulp van de toolbelt vg. Het is een lichte laag bovenop numpy en het ondersteunt enkele waarden en gestapelde vectoren.

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

Ik heb de bibliotheek gemaakt bij mijn laatste opstart, waar het werd gemotiveerd door gebruik als dit: eenvoudige ideeën die veel te uitgebreid zijn in NumPy.


Antwoord 7

v1 = np.array([ 1, 2 , 3 ])
v1_size = len(v1)
print(v1_size) // 3

Other episodes