2015-10-25 9 views
5

मुझे एक बड़ी NumPy सरणी की गणना करने में रुचि है। मेरे पास एक बड़ी सरणी A है जिसमें संख्याओं का एक समूह शामिल है। मैं इन संख्याओं के विभिन्न संयोजनों के योग की गणना करना चाहता हूं। यदि इस गणना करने के लिए एक और अधिक सुरुचिपूर्ण और स्मृति कारगर तरीका हैबड़े NumPy गुणा Vectorize

A = np.random.uniform(0,1, (3743, 1388, 3)) 
Combinations = np.random.randint(0,3, (306,3)) 
Final_Product = np.array([ np.sum(A*cb, axis=2) for cb in Combinations]) 

मेरा प्रश्न है: डेटा की संरचना इस प्रकार है? मुझे np.dot() के साथ काम करने में निराशा होती है जब 3-डी सरणी शामिल होती है।

यदि यह मदद करता है, तो Final_Product का आकार आदर्श रूप से होना चाहिए (3743, 306, 1388)। वर्तमान में Final_Product आकार (306, 3743, 1388) का है, इसलिए मैं वहां पहुंचने के लिए बस पुनः आकार दे सकता हूं।

उत्तर

5

np.dot() आपको वांछित आउटपुट नहीं देगा, जब तक कि आप अतिरिक्त चरण नहीं लेते हैं जिसमें शायद reshaping शामिल होगा। यहाँ np.einsum का उपयोग कर किसी भी अतिरिक्त स्मृति भूमि के ऊपर के बिना यह एक शॉट करने के लिए एक vectorized दृष्टिकोण है -

Final_Product = np.einsum('ijk,lk->lij',A,Combinations) 

के लिए पूर्णता, यहाँ np.dot और reshaping साथ के रूप में पहले चर्चा -

M,N,R = A.shape 
Final_Product = A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N) 

रनटाइम परीक्षण और उत्पादन की पुष्टि -

In [138]: # Inputs (smaller version of those listed in question) 
    ...: A = np.random.uniform(0,1, (374, 138, 3)) 
    ...: Combinations = np.random.randint(0,3, (30,3)) 
    ...: 

In [139]: %timeit np.array([ np.sum(A*cb, axis=2) for cb in Combinations]) 
1 loops, best of 3: 324 ms per loop 

In [140]: %timeit np.einsum('ijk,lk->lij',A,Combinations) 
10 loops, best of 3: 32 ms per loop 

In [141]: M,N,R = A.shape 

In [142]: %timeit A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N) 
100 loops, best of 3: 15.6 ms per loop 

In [143]: Final_Product =np.array([np.sum(A*cb, axis=2) for cb in Combinations]) 
    ...: Final_Product2 = np.einsum('ijk,lk->lij',A,Combinations) 
    ...: M,N,R = A.shape 
    ...: Final_Product3 = A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N) 
    ...: 

In [144]: print np.allclose(Final_Product,Final_Product2) 
True 

In [145]: print np.allclose(Final_Product,Final_Product3) 
True 
+0

धन्यवाद! मैंने @ajcr का उत्तर भी बहुत उपयोगी पाया। टेंसर का उपयोग करके मैंने 'np.einsum' – Julien

+0

@ जूलियन I में इस्तेमाल किए गए समय को भी घटा दिया Ijcr का समाधान भी पसंद है! मुझे लगता है कि यह 'डॉट' क्या है इसका एक संक्षिप्त संस्करण है। – Divakar

5

इंस्टेंट dot का ईड आप tensordot का उपयोग कर सकते हैं। सही क्रम में डाल करने के लिए कुल्हाड़ियों

np.tensordot(A, Combinations, [2, 1]).transpose(2, 0, 1) 

नोट अंत में transpose: आपके वर्तमान विधि के बराबर है।

dot की तरह, tensordot फ़ंक्शन तेजी से BLAS/LAPACK लाइब्रेरीज़ (यदि आपने उन्हें इंस्टॉल किया है) पर कॉल कर सकते हैं और इसलिए बड़े सरणी के लिए अच्छा प्रदर्शन करना चाहिए।

+0

लघु और सरल, मुझे यह पसंद है! – Divakar

+0

@ दिवाकर: धन्यवाद! मैं अभी भी 'einsum' पसंद करते हैं हालांकि :-) –

+0

मुझे भी !! मुझे यह एहसास था जब 'ईन्सम' एक 3 डी सरणी डालता है, यह '2 डी' सरणी में कमी या सबसे अच्छा 'स्केलर' के रूप में उतना कुशल नहीं है। – Divakar

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