2013-10-07 3 views
5

क्यों अजगर की इस पंक्तिअजगर कोड पाश गति तुलना

yy = [sum(y[i:i+5])/5. for i in range(len(y)-4)] 

रन कुछ 20 बार निम्नलिखित (समकक्ष) कोड की तुलना में तेजी है?

for i in xrange(0,len(y)-4):  
    yy = np.append(yy, sum(y[i:i+5])/5.) 

जहां y वास्तविकताओं की एक बड़ी श्रृंखला है। हुड के नीचे वास्तव में क्या चल रहा है? बहुत धन्यवाद।

+0

आप अभी भी पहले उदाहरण में xrange का उपयोग कर सकते हैं, इसे थोड़ा और तेज कर सकते हैं। – gregb212

+0

सूची की समझ लूप्स से तेज होती है। Http://stackoverflow.com/questions/2849645/in-python-is-it-better-to-use-list-comprehensions-or-for-each-loops – tom

+0

जब आप कहते हैं कि ये समकक्ष हैं तो आपका क्या मतलब है?न्यूमपी के 'एपेंड' को देखते हुए, यह न्यूमपी के 'कॉन्सटेनेट' को बुलाता है जो कम से कम मास्क किए गए सरणी के लिए अतिरिक्त जांच करता है। इसके अतिरिक्त, सरणी में जोड़ना अक्सर अधिक महंगा होता है, इसलिए मुझे यकीन नहीं है कि यह परिणाम काउंटर-अंतर्ज्ञानी है। – ely

उत्तर

3

दो कोड समकक्ष नहीं हैं। सही बराबर संस्करण है:

yy = [] 
for i in range(0,len(y)-4):  
    yy.append(sum(y[i:i+5])/5.) 

कौन सा एक ही समय के बारे में लेता है:

In [10]: y = [1.0] * 100000 

In [11]: %timeit [sum(y[i:i+5])/5. for i in range(len(y)-4)] 
10 loops, best of 3: 49.6 ms per loop 

In [12]: %%timeit yy = [] 
    ...: for i in range(0,len(y)-4):  
    ...:  yy.append(sum(y[i:i+5])/5.) 
    ...: 
10 loops, best of 3: 55.1 ms per loop 

समस्या numpy.append करने के लिए कॉल जो list.append तुलना में बहुत धीमी है। यह शायद इस तथ्य के कारण है कि numpy.appendएक प्रतिलिपि सरणी के प्रति बना रहा है और प्रत्येक प्रविष्टि के लिए इसे लौटा रहा है। पहली प्रविष्टि लागत 2 (1 तत्व के लिए स्थान आवंटित करें और इसे कॉपी करें)। सेकंड की लागत (2 तत्वों के लिए स्थान आवंटित करें, एकमात्र तत्व की प्रतिलिपि बनाएँ और नया)। तीसरी लागत 4 (3 के लिए आवंटित, 2 तत्वों की प्रतिलिपि बनाएँ और नया)। आदि

इसका मतलब है कि एल्गोरिथ्म अचानक O(n^2) बन गया है, जबकि यह O(n) अजगर list रों का उपयोग कर के बाद से वे नहीं हर append के लिए पूरी सूची कॉपी कर सकता है। वे अधिक तत्वों को समायोजित करने के लिए अधिक स्मृति आवंटित करने के लिए पर्याप्त स्मार्ट हैं।

इसके अलावा, एक सामान्य नियम के रूप में, numpy सिंगल-एलिमेंट एक्सेस के लिए चमक नहीं है। यह वास्तव में धीमी उस मामले में शुद्ध पायथन की तुलना में है, क्योंकि इसे हर समय मशीन डेटा प्रकारों और पायथन वस्तुओं के बीच परिवर्तित करना होता है। संचालन को सदिश बनाने की कोशिश करें और आपको बड़ी गति अप दिखाई देगी।

3

numpy को वेक्टरकृत ऑपरेशंस करने के लिए डिज़ाइन किया गया है: यदि आपको numpy.append पर कॉल करना है, तो प्रत्येक कॉल का ओवरहेड इसे लायक नहीं बनायेगा।

numpy में इस ऑपरेशन (रोलिंग का मतलब) करने का सही तरीका यह है कि इसे सदिश बनाना है, उदाहरण के लिए संकल्प समारोह का उपयोग करना (सुझाव के लिए @askewchan के लिए धन्यवाद)। उस मामले में यह दूर सूची समझ की तुलना में तेजी है:

import timeit 
import numpy as np 

y = np.random.normal(0, 1, 10000) 

print timeit.timeit("np.convolve(y, np.ones(5)/5, mode='valid')", 
        setup = "from __main__ import y; import numpy as np", 
        number=100) 

print timeit.timeit("[sum(y[i:i+5])/5. for i in range(len(y)-4)]", 
        setup = "from __main__ import y", 
        number=100) 

मेरी मशीन पर, numpy vectorized समाधान के 100 पुनरावृत्तियों 0.03 सेकंड का समय लगता है, जबकि सूची समझ 6.56 सेकंड लेता है।

+2

रोलिंग मतलब करने के लिए यह वास्तव में एक अच्छा लेकिन जटिल तरीका है, इसे केवल 'std' जैसे फ़ंक्शन करने में सक्षम होना बहुत ही शानदार होना चाहिए। 'माध्य' के लिए, एक आसान (और वास्तव में, तेज़) समाधान' np.convolve (ए, np.ones (5)/5, मोड = 'मान्य') ' – askewchan

+0

@askewchan: उत्कृष्ट विचार: मैंने अपना बदल दिया है समाधान –

+0

'np.correlate (y, np.ones (5)/5) का उपयोग करने का समाधान एक और विकल्प है। मैंने इसे समय दिया, और यह मेरी मशीन पर 'convolve' विधि से थोड़ा तेज है। – Akavall

संबंधित मुद्दे