Reputation: 11
I am trying to implement a matrix filtering in Python, and so far the implementation appears to be very slow and inefficient. I wonder if there is an efficient way of performing such filtering.
Provided a large matrix A and a filtering matrix M, the function should return a "remixed" matrix R which is obtained by multiplying each element (i,j) of A by M, then the result is superposed/inserted into R at position (i,j). Please find below the code that is expected to do this.
The example below takes about 68 sec (!) at my computer, which seems very inefficient.
I would be very grateful if you could recommend the way to speed-up this function. Many thanks in advance!
import numpy as np
import time
nx = ny = 1500
n_mix = 50
# matrix to be filtered
A = np.random.random_sample( (nx, ny) )
# filter to be applied to each point:
M = np.random.random_sample( (2*n_mix+1, 2*n_mix+1) )
# the result is stored in "remix":
remix = np.zeros_like(A)
start = time.time()
for i in range(n_mix, nx-n_mix):
for j in range(n_mix, ny-n_mix):
remix[i - n_mix:i + n_mix + 1, j - n_mix:j + n_mix + 1 ] += M * A[i,j]
print remix
duration = time.time() - start
print(round(duration))
UPDATE
In fact the ndimage package in scipy has the general convolution function that does the job. I post below the 3 variants of doing the filtering, with respected times. The fastest is with ndimage.convolution (24 seconds vs. 56 and 68 by other methods). However, it still seems rather slow...
import numpy as np
from scipy import ndimage
import time
import sys
def remix_function(A, M):
n = (np.shape(M)[0]-1)/2
R = np.zeros_like(A)
for k in range(-n, n+1):
for l in range(-n, n+1):
# Ak = np.roll(A, -k, axis = 0)
# Akl = np.roll(Ak, -l, axis = 1)
R += np.roll(A, (-k,-l), axis = (0,1) ) * M[n-k, n-l]
return R
if __name__ == '__main__':
np.set_printoptions(precision=2)
nx = ny = 1500
n_mix = 50
nb = 2*n_mix+1
# matrix to be filtered
A = np.random.random_sample( (nx, ny) )
# filter to be applied to each point:
M = np.random.random_sample( (nb, nb) )
# the result is stored in "remix":
remix1 = np.zeros_like(A)
remix2 = np.zeros_like(A)
remix3 = np.zeros_like(A)
#------------------------------------------------------------------------------
# var 1
#------------------------------------------------------------------------------
start = time.time()
remix1 = remix_function(A, M)
duration = time.time() - start
print('time for var1 =', round(duration))
#------------------------------------------------------------------------------
# var 2
#------------------------------------------------------------------------------
start = time.time()
for i in range(n_mix, nx-n_mix):
for j in range(n_mix, ny-n_mix):
remix2[i - n_mix:i + n_mix + 1, j - n_mix:j + n_mix + 1 ] += M * A[i,j]
duration = time.time() - start
print('time for var2 =', round(duration))
#------------------------------------------------------------------------------
# var 3
#------------------------------------------------------------------------------
start = time.time()
remix3 = ndimage.convolve(A, M)
duration = time.time() - start
print('time for var3 (convolution) =', round(duration))
Upvotes: 1
Views: 93
Reputation: 2161
I can't comment on posts yet, but your double for loop is the problem. Have you tried defining a function and then using np.vectorize?
Upvotes: 1