2013-09-05 10 views
9

मेरे पास एक सरणी है और मैं 2x2 गैर-ओवरलैपिंग विंडो को स्कैन करके और अधिकतम प्राप्त करके एक छोटी सरणी बनाना चाहता हूं।विंडो में अधिकतम अधिकतम

import numpy as np 

np.random.seed(123) 
np.set_printoptions(linewidth=1000,precision=3) 
arr = np.random.uniform(-1,1,(4,4)) 
res = np.zeros((2,2)) 
for i in xrange(res.shape[0]): 
    for j in xrange(res.shape[1]): 
     ii = i*2 
     jj = j*2 
     res[i][j] = max(arr[ii][jj],arr[ii+1][jj],arr[ii][jj+1],arr[ii+1][jj+1]) 

print arr 
print res 

तो इस तरह एक मैट्रिक्स:

[[ 0.393 -0.428 -0.546 0.103] 
[ 0.439 -0.154 0.962 0.37 ] 
[-0.038 -0.216 -0.314 0.458] 
[-0.123 -0.881 -0.204 0.476]] 

इस बन चाहिए: यहाँ एक उदाहरण है

[[ 0.439 0.962] 
[-0.038 0.476]]  

मैं कैसे और अधिक कुशलता से ऐसा कर सकते हैं?

+0

क्या आप हमें दिखा सकते हैं कि आपने क्या प्रयास किया है और यह क्यों काम नहीं किया है? –

+0

उपर्युक्त कोड आवश्यक नौकरी करता है, लेकिन इसे तेज़ होने की आवश्यकता है और इसलिए मैं लूप –

+1

को निकालना चाहता हूं [NumBa] (http://numba.pydata.org/) का उपयोग करने पर विचार करें। आप अपनी डबल लूप को वैसे ही छोड़ सकते हैं, सजावट में लगभग 10 अक्षर जोड़ें, और इसके लिए सी-जैसे प्रदर्शन प्राप्त करें। यदि आप Continuum Analytics '["Anaconda"] (https://store.continuum.io/cshop/anaconda/) पायथन के वितरण के साथ काम करते हैं तो आउट ऑफ़ द बॉक्स का उपयोग करना आसान है। – ely

उत्तर

9

आप ऐसा कर सकते हैं:

print arr.reshape(2,2,2,2).swapaxes(1,2).reshape(2,2,4).max(axis=-1) 

[[ 0.439 0.962] 
[-0.038 0.476]] 

के साथ शुरू की व्याख्या:

arr=np.array([[0.393,-0.428,-0.546,0.103], 
[0.439,-0.154,0.962,0.37,], 
[-0.038,-0.216,-0.314,0.458], 
[-0.123,-0.881,-0.204,0.476]]) 

हम पहले समूह के लिए प्रासंगिक वर्गों में कुल्हाड़ियों चाहते हैं।

tmp = arr.reshape(2,2,2,2).swapaxes(1,2) 
print tmp  

[[[[ 0.393 -0.428] 
    [ 0.439 -0.154]] 

    [[-0.546 0.103] 
    [ 0.962 0.37 ]]] 


[[[-0.038 -0.216] 
    [-0.123 -0.881]] 

    [[-0.314 0.458] 
    [-0.204 0.476]]]] 

नयी आकृति प्रदान करना एक बार डेटा के समूहों प्राप्त करने के लिए और अधिक हम चाहते हैं:

tmp = tmp.reshape(2,2,4) 
print tmp 

[[[ 0.393 -0.428 0.439 -0.154] 
    [-0.546 0.103 0.962 0.37 ]] 

[[-0.038 -0.216 -0.123 -0.881] 
    [-0.314 0.458 -0.204 0.476]]] 

अंत में पिछले अक्ष के साथ अधिकतम ले लो।

इस वर्ग मैट्रिक्स के लिए सामान्यीकृत किया जा सकता है, के लिए:

k = arr.shape[0]/2 
arr.reshape(k,2,k,2).swapaxes(1,2).reshape(k,k,4).max(axis=-1) 

जेमी और Dougal की टिप्पणी है कि हम इस आगे सामान्यीकरण कर सकते हैं के बाद:

n = 2     #Height of window 
m = 2     #Width of window 
k = arr.shape[0]/n #Must divide evenly 
l = arr.shape[1]/m #Must divide evenly 
arr.reshape(k,n,l,m).max(axis=(-1,-3))    #Numpy >= 1.7.1 
arr.reshape(k,n,l,m).max(axis=-3).max(axis=-1)  #Numpy < 1.7.1 
+0

वाह यह करता है। धन्यवाद –

+1

ध्यान दें कि सरणी वर्ग होने की आवश्यकता नहीं है, जब तक कि वे विभाजित हों; आप इसे 'k = arr.shape [0]/n में बदल सकते हैं; एल = arr.shape [1]/एन; arr.reshape (के, एन, एल, एन) .swapaxes (1, 2) .reshape (के, एल, एन * एन) .मैक्स (अक्ष = -1) ', मुझे लगता है। – Dougal

+4

अक्षों को स्वैप करने के बाद वह अंतिम पुनर्विक्रय पूर्ण सरणी की एक प्रति ट्रिगर करता है, जो बड़े सरणी के लिए महंगा हो सकता है।सबसे अच्छा विकल्प यह पूरी तरह से छोड़ना है और (numpy> 1.7 का उपयोग करके) अक्षरों का एक tuple '.max', यानी' arr.reshape (2,2,2,2) .max (axis = (- 1, - 3)) 'यहां तक ​​कि यदि आप numpy के पुराने संस्करण से फंस गए हैं, तो भी आप आधा डेटा कॉपी करेंगे यदि आप' .ax 'पर दो कॉल करते हैं, यानी' arr.reshape (2,2,2,2) .max (अक्ष = -3) .max (अक्ष = -1) '। – Jaime

2

मैं टिप्पणी क्षेत्र में उल्लेख किया है, NumBa का उपयोग करने पर विचार करें। आप अपनी डबल लूप को वैसे ही छोड़ सकते हैं, सजावट में लगभग 10 अक्षर जोड़ें, और इसके लिए सी-जैसे प्रदर्शन प्राप्त करें। अगर आप पाइथन के कंटिन्यूम एनालिटिक्स 'एनाकोंडा' वितरण के साथ काम करते हैं तो आउट ऑफ़ द बॉक्स का उपयोग करना आसान है।

यह न्यूमबा के लिए लगभग एक आदर्श उपयोग केस है क्योंकि यह एल्गोरिदम डबल लूप के साथ अधिक स्वाभाविक रूप से व्यक्त किया जाता है। रीशेपिंग दृष्टिकोण तेजी से सरणी संचालन का फायदा उठाता है, लेकिन यह बेहद अपठनीय है जब तक आप प्रोग्राम के लक्ष्य को पहले से ही नहीं जानते। इस तरह के कार्यों को विस्तारित रूप में छोड़ना और तथ्य के बाद कुछ और निम्न स्तर की भाषा में परिवर्तित करके गति प्राप्त करना बेहद वांछनीय है।

+0

मुझे numba और इसी गति से अवगत है, लेकिन मैं एक शुद्ध numpy समाधान की तलाश में था। धन्यवाद –

+4

मैं उत्सुक था कि इस समस्या पर वास्तव में कितना अच्छा होगा, इसलिए मैंने इसे एक शॉट दिया: http://nbviewer.ipython.org/c22a894f260d17876f01। इन कार्यों के थोड़ा-संशोधित संस्करणों के मेरे परीक्षण में, 200x200 मैट्रिक्स पर, मूल कोड 100ms लिया, numba JIT'd संस्करण ~ 85ms लिया, और @ ओफियन के संस्करण में 0.5ms लगे। स्केलिंग, 2k x 2k मैट्रिक्स numba पर 8s लिया और ओफियन 64ms लिया। ~ 150x स्पीडअप शायद पठनीयता में थोड़ा नुकसान के लायक हैं; क्या आप जानते हैं कि क्या मैं यहाँ कुछ गलत कर रहा हूं जिससे numba इतना खराब कर रहा है? – Dougal

+0

सुनिश्चित नहीं है, लेकिन इस तरह के कर्नेल के लिए, यह बहुत असामान्य लगता है। मैं नोटबुक पर एक नज़र डालेगा। – ely

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