Làm thế nào để bạn có được độ lớn của một vectơ trong Numpy?


157

Để phù hợp với "Chỉ có một cách rõ ràng để làm điều đó", làm thế nào để bạn có được độ lớn của một vectơ (mảng 1D) trong Numpy?

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

Các công việc trên, nhưng tôi không thể tin rằng tôi phải tự xác định một chức năng tầm thường và cốt lõi như vậy.


1
Tôi thường sử dụng linalg.normnhư được đề cập dưới đây. Nhưng hơi đơn giản hơn điều lambda của bạn, không có hàng nhập khẩu cần thiết, chỉ làsum(x*x)**0.5
wim

7
Nhân tiện, không bao giờ có bất kỳ lý do chính đáng nào để gán hàm lambda cho tên.
wim

@wim tại sao vậy? Tôi chỉ nên sử dụng defkhi khai báo một chức năng như vậy? Tôi nghĩ rằng nếu nó hợp pháp một dòng, nó làm cho nó dễ đọc hơn.
Nick T

6
lambda được dự định là một chức năng ẩn danh, vì vậy bằng cách đặt cho nó một cái tên bạn đang làm sai. Sau đó, nó chỉ là một phiên bản bị tê liệt của def. và, nếu bạn nhấn mạnh, bạn cũng có thể đặt def trên một dòng. địa điểm thông thường nơi bạn có thể được biện minh để sử dụng lambda là để sử dụng trong một số danh sách đối số dưới dạng có thể gọi được. những người sử dụng sai nó như được hiển thị ở trên là một lý do tại sao nó đưa nó vào danh sách những điều hối tiếc về trăn của guido (xem slide 4)
wim

6
Liên kết đã chết! Sống lâu liên kết!
daviewales

Câu trả lời:


209

Chức năng bạn đang theo đuổi là numpy.linalg.norm. (Tôi nghĩ rằng nó nên ở trong cơ sở numpy như là một thuộc tính của một mảng - nói x.norm()- nhưng tốt thôi).

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

Bạn cũng có thể cung cấp tùy chọn ordcho định mức thứ n bạn muốn. Giả sử bạn muốn 1-Norm:

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

Và như thế.


14
"Nên là một thuộc tính của một mảng: x.norm ()" Tôi hoàn toàn đồng ý. Thông thường khi làm việc với numpy, tôi sử dụng các lớp con Array và Matrix của riêng tôi có tất cả các hàm mà tôi thường sử dụng được kéo vào như các phương thức. Matrix.randn([5,5])
mdaoust

3
Ngoài ra, đối với các ma trận bao gồm các vectơ, np.linalg.normgiờ đây có một axisđối số mới , được thảo luận ở đây: stackoverflow.com/a/19794741/1959808
Ioannis Filippidis 18/11/13

95

Nếu bạn lo lắng về tốc độ, thay vào đó bạn nên sử dụng:

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

Dưới đây là một số điểm chuẩn:

>>> 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: Sự cải thiện tốc độ thực sự đến khi bạn phải lấy chỉ tiêu của nhiều vectơ. Sử dụng các hàm numpy thuần túy không yêu cầu bất kỳ vòng lặp nào. Ví dụ:

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
Tôi thực sự đã sử dụng phương pháp ít rõ ràng này sau khi nhận thấy đó np.linalg.normlà một nút cổ chai, nhưng sau đó tôi đã tiến thêm một bước và chỉ sử dụng math.sqrt(x[0]**2 + x[1]**2)đó là một cải tiến đáng kể khác.
Nick T

@NickT, hãy xem bản chỉnh sửa của tôi để biết sự cải thiện thực sự khi sử dụng các hàm numpy thuần túy.
dùng545424

2
Ứng dụng tuyệt vời của sản phẩm chấm!
vktec

1
numpy.linalg.normchứa các biện pháp bảo vệ chống tràn mà việc triển khai này bỏ qua. Ví dụ, hãy thử tính toán định mức của [1e200, 1e200]. Có một lý do nếu nó chậm hơn ...
Federico Poloni

@FedericoPoloni, ít nhất là với phiên bản numpy 1.13.3 tôi nhận được infkhi tính toán np.linalg.norm([1e200,1e200]).
dùng545424

16

Tuy nhiên, một cách khác là sử dụng einsumhàm trong numpy cho một trong hai mảng:

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

hoặc vectơ:

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

Tuy nhiên, dường như có một số chi phí liên quan đến việc gọi nó có thể làm cho nó chậm hơn với các đầu vào nhỏ:

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.normchứa các biện pháp bảo vệ chống tràn mà việc triển khai này bỏ qua. Ví dụ, hãy thử tính toán định mức của [1e200, 1e200]. Có một lý do nếu nó chậm hơn ...
Federico Poloni

7

Cách nhanh nhất tôi tìm thấy là thông qua Internal1d. Đây là cách nó so sánh với các phương pháp numpy khác:

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

Internal1d nhanh hơn ~ 3 lần so với linalg.norm và tóc nhanh hơn einsum


Trên thực tế từ những gì bạn viết ở trên, linalg.normlà nhanh nhất vì nó thực hiện 9 cuộc gọi trong 29ms, vì vậy 1 cuộc gọi trong 3.222ms so với 1 cuộc gọi trong 4.5ms cho inner1d.
patapouf_ai

@bisounours_tronconneuse sử dụng thời gian cho tổng thời gian thực hiện. Nếu bạn chạy mã ở trên, bạn sẽ nhận được sự cố về thời gian cho mỗi cuộc gọi chức năng. Nếu bạn vẫn còn nghi ngờ, thay đổi số lượng vector để một cái gì đó rất rất lớn, giống như ((10**8,3,))và sau đó tự chạy np.linalg.norm(V,axis=1)tiếp theo np.sqrt(inner1d(V,V)), bạn sẽ nhận thấy linalg.normsẽ tụt hậu so với inner1d
Fnord

Đồng ý. Cảm ơn bạn đã làm rõ.
patapouf_ai

numpy.linalg.normchứa các biện pháp bảo vệ chống tràn mà việc triển khai này bỏ qua. Ví dụ, hãy thử tính toán định mức của [1e200, 1e200]. Có một lý do nếu nó chậm hơn ...
Federico Poloni

3

sử dụng định mức hàm trong scipy.linalg (hoặc 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

Bạn có thể làm điều này một cách chính xác bằng cách sử dụng toolbelt vg . Đó là một lớp ánh sáng trên đỉnh của numpy và nó hỗ trợ các giá trị đơn và các vectơ xếp chồng lên nhau.

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

Tôi đã tạo ra thư viện ở lần khởi động cuối cùng của mình, nơi nó được thúc đẩy bởi những cách sử dụng như thế này: những ý tưởng đơn giản quá dài dòng trong NumPy.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.