I have a multidimensional numpy array where the elements are either True or False values:
import numpy as np
#just making a toy array grid to show what I want to do
grid = np.ones((4,4),dtype = 'bool')
grid[0,0]=False
grid[-1,-1]=False
#now grid has a few false values but is a 4x4 filled with mostly true values
Now I need to generate another array M, where the value at each site M[i,j] depends on grid[i:i+2,j:j+2] as in
M = np.empty((4x4)) #elements to be filled
#here is the part I want to clean up
for ii in range(4):
for jj in range(4):
#details here are unimportant. It's just that M[ii,jj] depends on
#multiple elements of grid in some way
if ii+2<=4 and jj+2<=4:
M[ii,jj] = np.all(grid[ii:ii+2,jj:jj+2]==True)
else:
M[ii,jj] = False
Is there some way to fill the array M using elements from grid without double loops?
Approach #1
Here's one approach with 2D
convolution -
from scipy.signal import convolve2d as conv2
out = (conv2(grid,np.ones((2,2),dtype=int),'valid')==4).astype(int)
Sample run -
In [118]: grid
Out[118]:
array([[False, True, True, True],
[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, False]], dtype=bool)
In [119]: (conv2(grid,np.ones((2,2),dtype=int),'valid')==4).astype(int)
Out[119]:
array([[0, 1, 1],
[1, 1, 1],
[1, 1, 0]])
Please note that the last row and last column from the expected output would be all zeros with the initialized output array. This is because of the sliding nature of the code, as it won't have that much of extent along the rows and columns.
Approach #2
Here's another with 2D
uniform filter -
from scipy.ndimage.filters import uniform_filter as unif2d
out = unif2d(grid,size=2).astype(int)[1:,1:]
Approach #3
Here's another with 4D
slided windowed view -
from skimage.util import view_as_windows as viewW
out = viewW(grid,(2,2)).all(axis=(2,3)).astype(int)
With that all(axis=(2,3))
, we are just checking along both the dimensions of every window for all elements to be all True
elements.
Runtime test
In [122]: grid = np.random.rand(5000,5000)>0.1
In [123]: %timeit (conv2(grid,np.ones((2,2),dtype=int),'valid')==4).astype(int)
1 loops, best of 3: 520 ms per loop
In [124]: %timeit unif2d(grid,size=2).astype(int)[1:,1:]
1 loops, best of 3: 210 ms per loop
In [125]: %timeit viewW(grid,(2,2)).all(axis=(2,3)).astype(int)
1 loops, best of 3: 614 ms per loop
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With