如何获得Numpy中向量的大小?


157

遵循“只有一种明显的方法”,如何在Numpy中获得向量(一维数组)的大小?

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

上面的方法有效,但是我不敢相信自己必须指定这样一个琐碎而核心的功能。


1
我通常使用linalg.norm如下所述。但是,比您的lambda事情稍微简单一点,不需要进口,只是sum(x*x)**0.5
wim 2012年

7
顺便说一句,从来没有任何理由将lambda函数分配给名称。
2012年

@wim为什么?我应该只def在声明这样的函数时使用?我认为,如果这是合法的一行,它将使其更易于阅读。
尼克T

6
lambda旨在成为一个匿名函数,因此通过给它一个名称来表示您做错了。那只是def的残缺版本。而且,如果您坚持认为,也可以在一条线上放一个def。通常可能需要使用lambda的地方是将一些参数列表作为可调用函数传入。人们如上所示
滥用

6
链接已死!链接万岁!
daviewales 2014年

Answers:


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
Ioannis 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)这是另一个重大改进。
尼克T

@NickT,请参阅我的编辑,以了解使用纯numpy函数时的真正改进。
user545424 2013年

2
点产品的酷应用!
vktec

1
numpy.linalg.norm包含针对此实现跳过的安全措施。例如,尝试计算的范数[1e200, 1e200]。如果慢一点是有原因的……
Federico Poloni

@FedericoPoloni,至少在numpy 1.13.3版本中,我inf在计算时得到了np.linalg.norm([1e200,1e200])
user545424 '19

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次通话,而for则在4.5ms内进行了1次通话inner1d
patapouf_ai 2016年

@bisounours_tron使用总执行时间的时间。如果您运行上面的代码,您将获得每个函数调用时序的细分。如果您还有疑问,改变矢量计数的东西非常非常大的,像((10**8,3,))然后手动运行np.linalg.norm(V,axis=1)之后np.sqrt(inner1d(V,V)),你会发现linalg.norm将滞后相比inner1d
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中过于冗长。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.