I have an array for an example:
import numpy as np
data=np.array([[4,4,4,1,1,1,1,1,1,0,0,1,1,1,1],
[3,0,0,1,1,1,1,1,1,1,1,1,1,1,0],
[6,0,0,1,1,1,1,1,1,0,0,0,1,1,0]])
Requirement :
In the data array, if element 1's are consecutive as the square size of ((3,3)) and more than square size no changes. Otherwise, replace element value 1 with zero except for the matching square size ((3,3))
Expected output :
[[4,4,4,0,1,1,1,1,1,1,0,0,0,0,0],
[3,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
[6,0,0,0,1,1,1,1,1,1,0,0,0,0,0]]
CodePudding user response:
I will provide here as solutions two different approaches. One which doesn't and one which is using Python loops. Let's start with the common header:
import numpy as np
from skimage.util import view_as_windows as winview
data=np.array([[4,4,4,0,1,1,1,0,0,0,0,1,0,0,1],
[3,0,0,1,1,1,1,1,1,1,1,0,0,1,0],
[6,0,0,1,1,1,1,1,0,0,0,0,1,0,0]])
Below an approach without using Python loops resulting in shortest code, but requiring import of an additional module skimage
:
clmn = np.where(np.all(winview(data,(3,3))[0],axis=(1,2)))[0][0]
data[data == 1] = 0 # set all ONEs to zero
data[0:3,clmn 3:] = 0 # set after match to zero
data[0:3,clmn:clmn 3] = 1 # restore ONEs
Another one is using Python loops and only two lines longer:
for clmn in range(0,data.shape[1]):
if np.all(data[0:3,clmn:clmn 3]):
data[data==1] = 0
data[0:3,clmn 3:] = 0
data[0:3,clmn:clmn 3] = 1
break
Instead of explaining how the above code using loops works I have put the 'explanations' into the names of the used variables so the code becomes hopefully self-explaining. With this explanations and some redundant code you can use the code below for another shaped haystack to search for in another array of same kind. For an array with more rows as the shape of the sub-array there will be necessary to loop also over the rows and optimize the code skipping some unnecessary checks.
import numpy as np
data=np.array([[4,4,4,0,1,1,1,0,0,0,0,1,0,0,1],
[3,0,0,1,1,1,1,1,1,1,1,0,0,1,0],
[6,0,0,1,1,1,1,1,0,0,0,0,1,0,0]])
indx_of_clmns_in_shape = 1
indx_of_rows_in_shape = 0
subarr_shape = (3, 3)
first_row = 0
first_clmn = 0
for clmn in range(first_clmn,data.shape[indx_of_clmns_in_shape],1):
sub_data = data[
first_row:first_row subarr_shape[indx_of_rows_in_shape],
clmn:clmn subarr_shape[indx_of_clmns_in_shape]]
if np.all(sub_data):
data[data == 1] = 0
data[first_row : subarr_shape[indx_of_rows_in_shape],
clmn subarr_shape[indx_of_clmns_in_shape] : ] = 0
data[first_row : subarr_shape[indx_of_rows_in_shape],
clmn : clmn subarr_shape[indx_of_clmns_in_shape]] = 1
break
# print(sub_data)
print(data)
all three versions of the code give the same result:
[[4 4 4 0 1 1 1 0 0 0 0 0 0 0 0]
[3 0 0 0 1 1 1 0 0 0 0 0 0 0 0]
[6 0 0 0 1 1 1 0 0 0 0 0 0 0 0]]
CodePudding user response:
Should be easy to do with a double for loop and a second array
rows = len(source_array)
columns = len(source_array[0])
# Create a result array of same size
result_array = [[0 for _ in range(rows)] for _ in range(columns)]
for i in range(rows):
for j in range(columns):
# Copy non 1s
if source_array[i][j] != 1:
result_array[i][j] = source_array[i][j]
# if enough rows left to check then check
if i < rows - 3:
if j < columns - 3:
# Create set on the selected partition
elements = set(source_array[i][j:j 3] source_array[i 1][j:j 3] source_array[i 2][j:j 3])
# Copy 1s to new array
if len(elements) == 1 and 1 in elements:
for sq_i in range(i,i 3):
for sq_j in range(j,j 3):
result_array[sq_i][sq_j] = 1