Вот одна векторизованная идея, основанная на convolution
.Учитывая эти ограничения, кажется, что нам нужно редактировать только 0s
мест.Для каждого скользящего окна получите число 1 с, а затем число, отличное от NaN, которое определяет порог для принятия решения о том, являются ли 1 с большинством.Если это так, установите те места, которые также равны 0, как 1 с.
Реализация будет выглядеть примерно так -
from scipy.signal import convolve2d
def fill0s(a):
# Mask of NaNs
nan_mask = np.isnan(a)
# Convolution kernel
k = np.ones((3,3),dtype=int)
# Get count of 1s for each kernel window
ones_count = convolve2d(np.where(nan_mask,0,a),k,'same')
# Get count of elements per window and hence non NaNs count
n_elem = convolve2d(np.ones(a.shape,dtype=int),k,'same')
nonNaNs_count = n_elem - convolve2d(nan_mask,k,'same')
# Compare 1s count against half of nonNaNs_count for the first mask.
# This tells us if 1s are majority among non-NaNs population.
# Second mask would be of 0s in a. Use Combined mask to set 1s.
final_mask = (ones_count >= nonNaNs_count/2.0) & (a==0)
return np.where(final_mask,1,a)
Обратите внимание, что с тех пор мы выполняем равномерную фильтрацию с такого рода1s ядро, мы также можем использовать uniform_filter
.
Пример запуска -
In [232]: a
Out[232]:
array([[ 1., 1., 1., 0., 0.],
[ 1., 1., nan, 1., 1.],
[nan, 1., 1., 0., 1.],
[ 0., 0., 0., 0., 1.]])
In [233]: fill0s(a)
Out[233]:
array([[ 1., 1., 1., 1., 1.],
[ 1., 1., nan, 1., 1.],
[nan, 1., 1., 1., 1.],
[ 0., 0., 0., 1., 1.]])