2012-09-25 15 views
9

के साथ स्लिमिंग numpy सरणी मुझे स्लाइड्स लेने की आवश्यकता वाले पूर्णांक की एक बड़ी आयामी सरणी मिली है। यह छोटा है, मैं बस a[start:end] करता हूं। समस्या यह है कि मुझे इन स्लाइसों में से अधिक की आवश्यकता है। a[start:end] काम नहीं करता है अगर प्रारंभ और अंत सरणी हैं। इसके लिए लूप का उपयोग किया जा सकता है, लेकिन मुझे इसे यथासंभव तेज़ होने की आवश्यकता है (यह एक बाधा है), इसलिए एक देशी numpy समाधान का स्वागत किया जाएगा।अन्य सरणी

बेहतर तरीके से समझने के लिए, मैं इस है:

a = numpy.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], numpy.int16) 
start = numpy.array([1, 5, 7], numpy.int16) 
end = numpy.array([2, 10, 9], numpy.int16) 

और किसी भी तरह इस में यह करने की जरूरत है: (हालांकि @ mgilson की टिप्पणी नोटों के रूप में

[[1], [5, 6, 7, 8, 9], [7, 8]] 
+0

मैं यह समझने क्या 'start' और' end' है हो रही है इसके साथ करने के लिए। एक तरफ के रूप में, मुझे नहीं लगता कि आप इसे पूरी तरह से खराब में करने में सक्षम होंगे क्योंकि numpy arrays आयताकार होने की आवश्यकता है। – mgilson

+0

YOu स्टार्ट-एंड मानों को सूची में टुपल्स के रूप में बनाने का प्रयास कर सकता है। – Keith

+0

जैसा कि आपको कोई विचारधारात्मक समाधान नहीं लगता है, यदि आपको अधिक विचारों की आवश्यकता है, तो हो सकता है कि आप शायद बाद में इसके साथ क्या करें और स्लाइस में कुछ विशेष गुण हों। – seberg

उत्तर

1

यह नहीं एक "शुद्ध" numpy समाधान है , यह कैसे अनियमित उत्पादन एक numpy सरणी हो सकता है देखने के लिए) कठिन है, लेकिन:

a = numpy.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], numpy.int16) 
start = numpy.array([1, 5, 7], numpy.int16) 
end = numpy.array([2, 10, 9], numpy.int16) 

map(lambda range: a[range[0]:range[1]],zip(start,end)) 

आप हो जाता है:

[array([1], dtype=int16), array([5, 6, 7, 8, 9], dtype=int16), array([7, 8], dtype=int16)] 

आवश्यकतानुसार।

5

ऐसा करने के लिए कोई स्पष्ट तरीका नहीं है। ध्यान दें कि चूंकि यह अनियमित है, यह केवल सरणी/स्लाइस की सूची होगी। हालांकि मैं इसे सभी (बाइनरी) ufuncs के लिए जोड़ना चाहता हूं जो लगभग सभी कार्यों में numpy (या वे कम से कम उन पर आधारित हैं) हैं, reduceat विधि है, जो वास्तव में स्लाइस की सूची बनाने से बचने में आपकी मदद कर सकती है, और इस तरह, अगर स्लाइस छोटे हैं, ऊपर गणना भी की गति:

In [1]: a = np.arange(10) 

In [2]: np.add.reduceat(a, [0,4,7]) # add up 0:4, 4:7 and 7:end 
Out[2]: array([ 6, 15, 24]) 

In [3]: np.maximum.reduceat(a, [0,4,7]) # maximum of each of those slices 
Out[3]: array([3, 6, 9]) 

In [4]: w = np.asarray([0,4,7,10]) # 10 for the total length 

In [5]: np.add.reduceat(a, w[:-1]).astype(float)/np.diff(w) # equivalent to mean 
Out[5]: array([ 1.5, 5. , 8. ]) 

संपादित करें: चूंकि आपके स्लाइस ओवरलैप, मैं जोड़ देगा कि यह ठीक भी है:

# I assume that start is sorted for performance reasons. 
reductions = np.column_stack((start, end)).ravel() 
sums = np.add.reduceat(a, reductions)[::2] 

[::2] कोई बड़ा होना चाहिए सामान्य रूप से यहां सौदे करें, क्योंकि ओवरलैपिंग स्लाइस के लिए कोई वास्तविक अतिरिक्त काम नहीं किया जाता है।

स्लाइस के साथ यहां एक समस्या है जिसके लिए stop==len(a) है। इससे बचा जाना चाहिए। आप इसके साथ ठीक एक टुकड़ा है, तो आप सिर्फ reductions = reductions[:-1] कर सकता है (अपने पिछले एक हैं), लेकिन अन्यथा आप बस reduceat चाल करने के लिए a के लिए एक मूल्य संलग्न करने के लिए की आवश्यकता होगी:

a = np.concatenate((a, [0])) 

के रूप में एक मूल्य को जोड़ने अंत में कोई फर्क नहीं पड़ता क्योंकि आप स्लाइस पर काम करते हैं।

7

यह (लगभग?) शुद्ध numpy में मुखौटा सरणी और घुमावदार चाल का उपयोग कर किया जा सकता है।

>>> indices = numpy.arange(a.size) 
>>> mask = ~((indices >= start[:,None]) & (indices < end[:,None])) 

या अधिक बस:

>>> mask = (indices < start[:,None]) | (indices >= end[:,None]) 

मुखौटा False (यानी मूल्यों नकाबपोश नहीं) है उन सूचियों के शुरू होने से मूल्य को >= और < अंत मान रहे हैं के लिए सबसे पहले, हम हमारे मुखौटा बनाने । (None के साथ स्लाइसिंग (उर्फ numpy.newaxis) प्रसारण को सक्षम करने वाला एक नया आयाम जोड़ता है।) अब हमारे मुखौटा इस तरह दिखता है:

>>> mask 
array([[ True, False, True, True, True, True, True, True, True, 
     True, True, True], 
     [ True, True, True, True, True, False, False, False, False, 
     False, True, True], 
     [ True, True, True, True, True, True, True, False, False, 
     True, True, True]], dtype=bool) 

अब हम सरणी फैलाने के लिए stride_tricks का उपयोग कर मुखौटा फिट करने के लिए है:

>>> as_strided = numpy.lib.stride_tricks.as_strided 
>>> strided = as_strided(a, mask.shape, (0, a.strides[0])) 
>>> strided 
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 
     [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 
     [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]], dtype=int16) 

यह एक 3x12 सरणी की तरह दिखता है, लेकिन एक ही में प्रत्येक पंक्ति अंक याद। अब हम उन्हें एक नकाबपोश सरणी में गठजोड़ कर सकते हैं:

>>> numpy.ma.array(strided, mask=mask) 
masked_array(data = 
[[-- 1 -- -- -- -- -- -- -- -- -- --] 
[-- -- -- -- -- 5 6 7 8 9 -- --] 
[-- -- -- -- -- -- -- 7 8 -- -- --]], 
      mask = 
[[ True False True True True True True True True True True True] 
[ True True True True True False False False False False True True] 
[ True True True True True True True False False True True True]], 
     fill_value = 999999) 

यह आप के लिए क्या पूछा के रूप में काफी समान नहीं है, लेकिन यह इसी तरह से व्यवहार करना चाहिए।

+0

कूल विचार, यह जानना दिलचस्प होगा कि यह दृष्टिकोण उनके उपयोग के लिए काम करता है (नए numpy संस्करणों पर)। वर्तमान में 'जहां' कीवर्ड 'ufunc' की कमी है (1.7 में भी कटौती के लिए यह नहीं होगा)। जिसका मतलब है कि आपकी स्ट्रिंग ट्रिक्स सरणी पूर्ण संस्करण में कॉपी की जाएगी, लगभग किसी भी चीज के लिए ... – seberg

+0

एमएमएच, 'ufunc' में' कहां 'की कमी * हाथ से समस्या के साथ कुछ भी नहीं है, और 'np.ma' आमतौर पर प्रतियों से बचाता है ... यह वास्तव में 'np.ma' (स्वयं में अच्छा विचार) का उपयोग करने का विषय नहीं है जो मुझे परेशान करता है, ऐसा लगता है कि यह शायद लूप या सूची समझ के साथ स्लाइड्स का निर्माण नहीं करेगा (केवल सरणी आकार को दोगुना करने के कारण) ... फिर भी, यह मजेदार है, +1 –

+0

@PierreGM, हाँ, मैं केवल वहां कम करने के कार्यों के बारे में सोचा था, लेकिन किसी बिंदु पर उन लोगों की इच्छा है ... – seberg

0

इसी तरह के समाधान जैसे timday। इसी प्रकार की गति:

a = np.random.randint(0,20,1e6) 
start = np.random.randint(0,20,1e4) 
end = np.random.randint(0,20,1e4) 

def my_fun(arr,start,end): 
     return arr[start:end] 

%timeit [my_fun(a,i[0],i[1]) for i in zip(start,end)] 
%timeit map(lambda range: a[range[0]:range[1]],zip(start,end)) 

100 loops, best of 3: 7.06 ms per loop 100 loops, best of 3: 6.87 ms per loop

0

आप एक पंक्ति में यह चाहते हैं, यह होगा:

x=[list(a[s:e]) for (s,e) in zip(start,end)] 
संबंधित मुद्दे