Если числа в каждой позиции относительно малы, al oop для отдельных значений, вероятно, даст вам гораздо лучшую производительность:
import numpy as np
m = np.array([
[0, 0, 4, 0, 0, 1],
[1, 0, 0, 0, 1, 0],
[2, 1, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0],
[-1, 0, -2, -3, 0, 0],
[0, 0, -1, -2, 0, -2],
[0, -5, 0 , -1, 0, -1] ])
result = np.ones(np.shape(m), dtype=int)
for d in np.unique(m):
if d == 0: continue
mask = m if d < 0 else m[::-1,:]
mask = np.cumsum(np.cumsum(mask==d,axis=0),axis=0)-1
mask = 1 - (mask>0)*(mask<=abs(d))
if d>0 : mask = mask[::-1,:]
result *= mask
#print(d)
#print(mask)
print(result)
Это обрабатывает каждое значение стирания индивидуально и генерирует маску для значение вверх или вниз. Результатом является пересечение всех масок.
Однако ... глядя на структуру чисел, я подозреваю, что числа стирания всегда будут в возрастающей / убывающей последовательности вокруг данной точки. Это может привести к гораздо более простому (и более быстрому) решению, когда вам нужно только обработать предыдущую и следующую строки, чтобы определить, нужно ли очищать точки:
result = np.ones(np.shape(m), dtype=int)
result[1:,:] *= m[:-1,:]>=0
result[:-1,:] *= m[1:,:] <=0
print(result)