2011-03-08 20 views
13

मेरे पास पहले 2 अक्षरों के साथ दो 2-डी सरणी हैं। पायथन में, मैं केवल दो अक्षरों के साथ दो मैट्रिस को संकुचित करना चाहता हूं। मैं पहले अक्ष के साथ संकल्प की गणना किए बिना नीचे C प्राप्त करना चाहता हूं।एक अक्ष के साथ कनवॉल्यूशन केवल

import numpy as np 
import scipy.signal as sg 

M, N, P = 4, 10, 20 
A = np.random.randn(M, N) 
B = np.random.randn(M, P) 

C = sg.convolve(A, B, 'full')[(2*M-1)/2] 

क्या कोई तेज़ तरीका है?

उत्तर

3

ndimage.convolve1d के साथ, आप अक्ष निर्दिष्ट कर सकते हैं ...

+1

उनका कहना है कि बाहर के लिए धन्यवाद। 'वजन' तर्क, हालांकि, 1-डी होना चाहिए। यह मेरे मामले में 2-डी है। – Paul

+0

@ पॉल: संदर्भ क्या है? वजन क्या हैं, बी? – Benjamin

+0

ए में प्रत्येक पंक्ति बी में इसी पंक्ति द्वारा फ़िल्टर की जा रही है। मैं इसे इस तरह कार्यान्वित कर सकता हूं, बस सोचा कि एक तेज़ तरीका हो सकता है। ए आकार में 10 गीगाबाइट के क्रम में है और मैं ओवरलैप-एड का उपयोग करता हूं। – Paul

8

आप np.apply_along_axis उपयोग कर सकते हैं वांछित अक्ष के साथ np.convolve लागू करने के लिए।

import numpy as np 

a = np.arange(10) 
a = np.vstack((a,a)).T 

filt = np.ones(3) 

np.apply_along_axis(lambda m: np.convolve(m, filt, mode='full'), axis=0, arr=a) 

यह एक आसान तरीका कई कार्यों है कि एक axis तर्क नहीं है सामान्यीकरण करने के लिए है: यहाँ एक 2d सरणी के लिए एक मालगाड़ी फ़िल्टर लागू करने का एक उदाहरण है।

+3

क्या इसमें प्रत्येक पंक्ति के साथ एक लूप बनाम कोई गति है? – endolith

+0

@endolith नोप, ऐसा नहीं है। [यह] देखें (http://stackoverflow.com/a/23849233/525169) उत्तर ... – Praveen

+0

'np.apply_along_axis' वास्तव में यहां उपयोग नहीं किया जा सकता है, क्योंकि ओपी चाहता है कि यह दो सरणीओं पर फिर से चालू हो जाए। ऐसा करने का तरीका बस एक लूप का उपयोग करना है, जैसा कि वर्णन किया गया है [यहां] (http: // stackoverflow।com/प्रश्न/28898858/अजगर से लागू के- बहु-सरणियों साथ अक्ष-)। – Praveen

3

np.apply_along_axis वास्तव में आपकी मदद नहीं करेगा, क्योंकि आप दो सरणी से अधिक पुन: प्रयास करने की कोशिश कर रहे हैं। प्रभावी रूप से, आपको here वर्णित अनुसार लूप का उपयोग करना होगा।

अब, यदि आपके सर छोटे हैं, तो लूप ठीक हैं, लेकिन यदि एन और पी बड़े हैं, तो आप शायद इसके बजाय घूमने के लिए एफएफटी का उपयोग करना चाहते हैं।

हालांकि, अगर आप उचित रूप से शून्य पैड अपने सरणियों पहले करने की जरूरत है, ताकि आपके "पूर्ण" घुमाव की उम्मीद आकार:

M, N, P = 4, 10, 20 
A = np.random.randn(M, N) 
B = np.random.randn(M, P) 

A_ = np.zeros((M, N+P-1), dtype=A.dtype) 
A_[:, :N] = A 
B_ = np.zeros((M, N+P-1), dtype=B.dtype) 
B_[:, :P] = B 

A_fft = np.fft.fft(A_, axis=1) 
B_fft = np.fft.fft(B_, axis=1) 
C_fft = A_fft * B_fft 

C = np.real(np.fft.ifft(C_fft)) 

# Test 
C_test = np.zeros((M, N+P-1)) 
for i in range(M): 
    C_test[i, :] = np.convolve(A[i, :], B[i, :], 'full') 

assert np.allclose(C, C_test) 
2
2 डी सरणियों के लिए

, समारोह scipy.signal.convolve2d तेजी से और scipy है .signal.fftconvolve भी तेजी से किया जा सकता है (सरणियों के आयामों के आधार पर):

यहाँ के साथ एन = 100000

import time  
import numpy as np 
import scipy.signal as sg 

M, N, P = 10, 100000, 20 
A = np.random.randn(M, N) 
B = np.random.randn(M, P) 

T1 = time.time() 
C = sg.convolve(A, B, 'full') 
print(time.time()-T1) 

T1 = time.time() 
C_2d = sg.convolve2d(A, B, 'full') 
print(time.time()-T1) 

T1 = time.time() 
C_fft = sg.fftconvolve(A, B, 'full') 
print(time.time()-T1) 

>>> 12.3 
>>> 2.1 
>>> 0.6 

जवाब एक ही कोड हैं सब इस्तेमाल किया अलग गणना के तरीकों की वजह से मामूली अंतर के साथ एक ही है (जैसे, fft प्रत्यक्ष गुणा बनाम, लेकिन मैं नहीं जानता कि क्या exaclty convolve2d का उपयोग करता है):

print(np.max(np.abs(C - C_2d))) 
>>>7.81597009336e-14 

print(np.max(np.abs(C - C_fft))) 
>>>1.84741111298e-13