कैसे आप Numpy में एक वेक्टर का परिमाण प्राप्त करते हैं?


157

"यह करने के लिए केवल एक ही स्पष्ट तरीका है" को ध्यान में रखते हुए, आप नम्पी में एक वेक्टर (1D सरणी) का परिमाण कैसे प्राप्त करते हैं?

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

उपरोक्त काम करता है, लेकिन मुझे विश्वास नहीं हो रहा है कि मुझे इस तरह के एक तुच्छ और मूल कार्य को निर्दिष्ट करना होगा।


1
मैं आमतौर पर linalg.normनीचे बताए अनुसार उपयोग करता हूं । लेकिन आपके लैम्ब्डा चीज़ की तुलना में थोड़ा सरल, बिना किसी आयात की आवश्यकता के, बस हैsum(x*x)**0.5
wim

7
वैसे, नाम के लिए लैम्ब्डा फ़ंक्शन को असाइन करने का कोई अच्छा कारण नहीं है।
विम

@ क्यों ऐसा क्यों है? मुझे केवल defउसी तरह एक फ़ंक्शन की घोषणा करते समय उपयोग करना चाहिए ? मुझे लगता है कि अगर यह वैध रूप से एक पंक्ति है, तो इसे पढ़ना आसान हो जाता है।
निक टी

6
लैम्ब्डा का उद्देश्य एक गुमनाम कार्य है, इसलिए इसे एक नाम देकर आप इसे गलत कर रहे हैं। यह सिर्फ तब अपंग का एक अपंग संस्करण है। और, यदि आप जोर देते हैं, तो आप एक पंक्ति में एक दोष भी डाल सकते हैं। सामान्य स्थान जहां आपको लैम्ब्डा का उपयोग करने के लिए उचित ठहराया जा सकता है, कॉल करने योग्य के रूप में कुछ तर्क सूची में पास करने के लिए है। लोग इसे गलत उपयोग कर रहे हैं, जैसा कि ऊपर दिखाया गया है, यही एक कारण है कि इसने इसे अजगर की पछतावा की सूची में पछतावा (4 स्लाइड देखें)
wim

जवाबों:


209

समारोह आप के बाद है numpy.linalg.norm। (मुझे लगता है कि यह एक सरणी की संपत्ति के रूप में आधार संख्या में होना चाहिए - कहते हैं x.norm()- लेकिन ओह अच्छी तरह से)।

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

आप चाहें ordतो nth ऑर्डर मानदंड के लिए वैकल्पिक में भी फीड कर सकते हैं। आप 1-मानदंड चाहते थे:

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

और इसी तरह।


14
"एक सरणी का गुण होना चाहिए: x.norm ()" मैं पूरी तरह से सहमत हूं। आमतौर पर जब मैं काम के साथ काम करता हूं तो मैं अपने खुद के एरे और मैट्रिक्स उपवर्गों का उपयोग करता हूं जिनके सभी कार्य हैं जो मैं आमतौर पर खींची गई विधियों के रूप में उपयोग करता हूं। Matrix.randn([5,5])
फेरे

3
इसके अलावा, वैक्टर में शामिल np.linalg.normaxis
मैट्रिस के लिए

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

EDIT: वास्तविक गति में सुधार तब आता है जब आपको कई वैक्टरों का आदर्श लेना होता है। शुद्ध सुन्न कार्यों का उपयोग करने के लिए छोरों के लिए किसी की आवश्यकता नहीं होती है। उदाहरण के लिए:

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)किया गया जो एक और महत्वपूर्ण सुधार था।
निक टी

@ सुन्न, शुद्ध सुन्न कार्यों का उपयोग करते समय वास्तविक सुधार के लिए मेरा संपादन देखें।
user545424

2
डॉट उत्पाद का कूल अनुप्रयोग!
vktec

1
numpy.linalg.normओवरफ़्लो के विरुद्ध सुरक्षा उपाय शामिल हैं जो इस कार्यान्वयन को छोड़ देता है। उदाहरण के लिए, के मान की गणना करने का प्रयास करें [1e200, 1e200]। धीमी होने की एक वजह है ...
फेडरिको पोलोनी

@FedericoPoloni, कम से कम संख्यात्मक संस्करण के साथ 1.13.3 मुझे infकंप्यूटिंग के समय मिलता है np.linalg.norm([1e200,1e200])
user545424

16

फिर भी एक अन्य विकल्प einsumया तो सरणियों के लिए कार्य का उपयोग करना है :

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]। धीमी होने की एक वजह है ...
फेडरिको पोलोनी

7

सबसे तेज़ तरीका जो मैंने पाया है वह इनर 1 डी के माध्यम से है। यहां बताया गया है कि यह अन्य संख्यात्मक विधियों की तुलना कैसे करता है:

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 की तुलना में ~ 3x तेज है और एक बाल जोइनसुम से तेज है


वास्तव में आप जो ऊपर लिखते हैं, linalg.normवह सबसे तेज़ है क्योंकि यह 29 कॉल में 9 कॉल करता है, इसलिए 3.222ms में 1 कॉल। इसके लिए 4.5 में 1 कॉल inner1d
patapouf_ai

कुल निष्पादन समय के लिए @bisounours_tronconneuse समय। यदि आप ऊपर का कोड चलाते हैं, तो आपको फंक्शन प्रति कॉल टाइमिंग का ब्रेकडाउन मिलेगा। आप अभी भी संदेह है, तो, बहुत बहुत बड़े कुछ करने के लिए वेक्टर गिनती बदलने की तरह ((10**8,3,))है और फिर मैन्युअल रूप से चलाना np.linalg.norm(V,axis=1)द्वारा पीछा किया np.sqrt(inner1d(V,V)), तो आप देखेंगे linalg.norminner1d की तुलना में अंतराल होगा
Fnord

ठीक। स्पष्टीकरण के लिए धन्यवाद।
patapouf_ai

numpy.linalg.normओवरफ़्लो के विरुद्ध सुरक्षा उपाय शामिल हैं जो इस कार्यान्वयन को छोड़ देता है। उदाहरण के लिए, के मान की गणना करने का प्रयास करें [1e200, 1e200]। धीमी होने की एक वजह है ...
फेडरिको पोलोनी

3

scipy.linalg (या 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

आप टूलबेल vg का उपयोग करके इसे संक्षिप्त रूप से कर सकते हैं । यह सुन्न के ऊपर एक हल्की परत है और यह एकल मूल्यों और स्टैक्ड वैक्टर का समर्थन करता है।

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

मैंने अपने आखिरी स्टार्टअप पर लाइब्रेरी बनाई, जहां यह इस तरह से उपयोग करने के लिए प्रेरित किया गया था: सरल विचार जो कि बहुत अधिक संख्या में वर्पी हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.