Given a matrix, I want to count number of filled elements (non-zero cells) adjacent to empty (zero) cells, where adjacency is along rows (left/right).
I have tried playing around with np.roll
and subtracting matrices, but I'm not sure how to code this without loops.
For example, given the matrix:
arr =
[[1 1 0 0 0 0 0 0 1 0]
[1 1 0 0 0 0 0 1 1 1]
[0 1 1 0 0 0 0 0 0 0]
[0 1 1 0 0 0 0 0 0 0]
[0 1 1 0 0 0 0 0 0 0]
[0 0 1 0 0 0 0 0 0 0]
[0 0 1 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]]
We have 12 non-zero elements adjacent to zeros.
Approach #1
We can use 2D convolution
to solve it with an appropriate kernel ([1,1,1])
or ([1,0,1])
on the zeros
mask and look for the convolution summations to be >=1
, which signals at least one zero in each sliding window of three elements and with an additional check of the current element being non-zero confirms that there's at least one neighboring 0
.
The implementation would look something like this -
In [245]: a # input array
Out[245]:
array([[1, 1, 0, 0, 0, 0, 0, 0, 1, 0],
[1, 1, 0, 0, 0, 0, 0, 1, 1, 1],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
In [246]: from scipy.signal import convolve2d
In [248]: k = [[1,1,1]] # kernel for convolution
In [249]: ((convolve2d(a==0,k,'same')>=1) & (a!=0)).sum()
Out[249]: 12
Approach #2
Another approach would be making use of slicing
as we would look for one-off offsetted elements along each row for the zeros and non-zeros matches for the left and right hand sides LHS
and RHS
and finally sum those -
maskRHS = (a[:,1:]==0) & (a[:,:-1]!=0)
maskLHS = (a[:,1:]!=0) & (a[:,:-1]==0)
maskRHS[:,1:] |= maskLHS[:,:-1]
out = maskRHS.sum() + maskLHS[:,-1].sum()
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