2013-12-17 9 views
10

मान लीजिए कि मैं NumPy सरणी की एक सूची का एक तत्व के लिहाज से योग करने के लिए चाहते हैं:जल्दी NumPy सरणी संक्षेप तत्व के लिहाज से

tosum = [rand(100,100) for n in range(10)] 

मैं यह करने के लिए सबसे अच्छा तरीका के लिए देख रहा हूँ। ऐसा लगता है numpy.sum की तरह भयंकर है:

timeit.timeit('sum(array(tosum), axis=0)', 
       setup='from numpy import sum; from __main__ import tosum, array', 
       number=10000) 
75.02289700508118 
timeit.timeit('sum(tosum, axis=0)', 
       setup='from numpy import sum; from __main__ import tosum', 
       number=10000) 
78.99106407165527 

कम बहुत तेजी से (परिमाण के लगभग दो आदेशों की धुन पर) है:

timeit.timeit('reduce(add,tosum)', 
       setup='from numpy import add; from __main__ import tosum', 
       number=10000) 
1.131795883178711 

यह भी कम करने की तरह दिखता है पर एक सार्थक नेतृत्व है गैर numpy योग (ध्यान दें कि इन 1E6 के लिए कर रहे हैं 1E4 चलाता है के बजाय ऊपर समय के लिए है कि):

timeit.timeit('reduce(add,tosum)', 
       setup='from numpy import add; from __main__ import tosum', 
       number=1000000) 
109.98814797401428 

timeit.timeit('sum(tosum)', 
       setup='from __main__ import tosum', 
       number=1000000) 
125.52461504936218 

वहाँ अन्य तरीकों मैं कोशिश करनी चाहिए रहे हैं? क्या कोई रैंकिंग की व्याख्या कर सकता है?


संपादित

numpy.sum निश्चित रूप से तेजी से करता है, तो सूची पहले एक numpy सरणी में बदल गया है:

tosum2 = array(tosum) 
timeit.timeit('sum(tosum2, axis=0)', 
       setup='from numpy import sum; from __main__ import tosum2', 
       number=10000) 
1.1545608043670654 

हालांकि, मैं केवल एक बार एक योग करने में रुचि हूँ , इसलिए सरणी को एक numpy सरणी में बदलना अभी भी एक असली प्रदर्शन जुर्माना होगा।

+2

मेरा अनुमान है कि 'np.sum' पहले बनाता है और सरणी और फिर इसे योग जो की व्याख्या करता है यह खराब प्रदर्शन ... मेरा अनुमान है कि है यह सबसे तेजी से हो सकता है अगर आप एक' एनपी पारित किया था। शुरू करने के लिए ndarray'। – mgilson

+1

और मैं उम्मीद करता हूं कि 'sum' को लगभग 1/11 तक कम करने की उम्मीद है क्योंकि यह' 0 + टॉसम [0] 'को छोड़कर 'sum' में निहित है। – mgilson

+0

यह समझ में आता है। मैं अलग-अलग सरणी के गुच्छा से शुरू करता हूं, इसलिए उन्हें पहले एक सुस्त सरणी में बदलना एक ही प्रदर्शन दंड होता है क्योंकि यह मेरे लिए योग करता है (क्योंकि मैं केवल एक बार योग कर रहा हूं)। – lnmaurer

उत्तर

4

निम्नलिखित reduce के साथ प्रतिस्पर्धी है, और tosum सूची के साथ पर्याप्त है। हालांकि, यह बहुत तेज नहीं है, और यह अधिक कोड है। मूल tosum के लिए

def loop_inplace_sum(arrlist): 
    # assumes len(arrlist) > 0 
    sum = arrlist[0].copy() 
    for a in arrlist[1:]: 
     sum += a 
    return sum 

समय (reduce(add, tosum) यकीन है कि सुंदर है।)। reduce(add, tosum) तेजी से होता है: सरणियों की एक बहुत लंबे समय तक सूची के लिए

In [128]: tosum = [rand(100,100) for n in range(10)] 

In [129]: %timeit reduce(add, tosum) 
10000 loops, best of 3: 73.5 µs per loop 

In [130]: %timeit loop_inplace_sum(tosum) 
10000 loops, best of 3: 78 µs per loop 

समय। अब loop_inplace_sum तेज है।

In [131]: tosum = [rand(100,100) for n in range(500)] 

In [132]: %timeit reduce(add, tosum) 
100 loops, best of 3: 5.09 ms per loop 

In [133]: %timeit loop_inplace_sum(tosum) 
100 loops, best of 3: 4.4 ms per loop 
+0

दिलचस्प। क्या आपके पास विचार है कि गति कहां से आती है? शायद यह कम करने से कम ओवरहेड है? (मैं सिर्फ एक साथ ~ 10 बड़े सरणी जोड़ रहा हूं, इसलिए शायद मैं कम से कम रहूंगा, लेकिन भविष्य के बारे में जानना अच्छा है।) – lnmaurer

+0

हां, कम ओवरहेड: इन-प्लेस अतिरिक्त कुछ ऑब्जेक्ट सृजन को समाप्त करता है। यदि आप 'sum = sum + a' के साथ' sum + = a' को प्रतिस्थापित करते हैं, तो यह 'कम' से थोड़ा धीमा हो जाता है। –

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