Замена элементов Numpy при выполнении условия
У меня есть массив с большими числами, который мне нужно манипулировать так, чтобы каждый элемент был изменен либо на 1, либо на 0, если условие выполнено (будет использоваться в качестве пиксельной маски позже). В массиве насчитывается около 8 миллионов элементов, и мой текущий метод слишком долго подходит для конвейера восстановления:
for (y,x), value in numpy.ndenumerate(mask_data):
if mask_data[y,x]<3: #Good Pixel
mask_data[y,x]=1
elif mask_data[y,x]>3: #Bad Pixel
mask_data[y,x]=0
Есть ли функция numpy, которая ускорит это?
Ответы
Ответ 1
>>> import numpy as np
>>> a = np.random.randint(0, 5, size=(5, 4))
>>> a
array([[4, 2, 1, 1],
[3, 0, 1, 2],
[2, 0, 1, 1],
[4, 0, 2, 3],
[0, 0, 0, 2]])
>>> b = a < 3
>>> b
array([[False, True, True, True],
[False, True, True, True],
[ True, True, True, True],
[False, True, True, False],
[ True, True, True, True]], dtype=bool)
>>>
>>> c = b.astype(int)
>>> c
array([[0, 1, 1, 1],
[0, 1, 1, 1],
[1, 1, 1, 1],
[0, 1, 1, 0],
[1, 1, 1, 1]])
Вы можете сократить это с помощью:
>>> c = (a < 3).astype(int)
Ответ 2
>>> a = np.random.randint(0, 5, size=(5, 4))
>>> a
array([[0, 3, 3, 2],
[4, 1, 1, 2],
[3, 4, 2, 4],
[2, 4, 3, 0],
[1, 2, 3, 4]])
>>>
>>> a[a > 3] = -101
>>> a
array([[ 0, 3, 3, 2],
[-101, 1, 1, 2],
[ 3, -101, 2, -101],
[ 2, -101, 3, 0],
[ 1, 2, 3, -101]])
>>>
См., Например, Индексирование с булевыми массивами.
Ответ 3
Самый быстрый (и самый гибкий) способ - использовать np.where, который выбирает между двумя массивами в соответствии с маской (массив истинных и ложных значений):
import numpy as np
a = np.random.randint(0, 5, size=(5, 4))
b = np.where(a<3,0,1)
print('a:',a)
print()
print('b:',b)
который будет производить:
a: [[1 4 0 1]
[1 3 2 4]
[1 0 2 1]
[3 1 0 0]
[1 4 0 1]]
b: [[0 1 0 0]
[0 1 0 1]
[0 0 0 0]
[1 0 0 0]
[0 1 0 0]]
Ответ 4
Вы можете создать массив масок за один шаг, как это
mask_data = input_mask_data < 3
Это создает логический массив, который затем может использоваться в качестве пиксельной маски. Обратите внимание: мы не изменили входной массив (как в вашем коде), но создали новый массив для хранения данных маски - я бы рекомендовал сделать это таким образом.
>>> input_mask_data = np.random.randint(0, 5, (3, 4))
>>> input_mask_data
array([[1, 3, 4, 0],
[4, 1, 2, 2],
[1, 2, 3, 0]])
>>> mask_data = input_mask_data < 3
>>> mask_data
array([[ True, False, False, True],
[False, True, True, True],
[ True, True, False, True]], dtype=bool)
>>>
Ответ 5
Я не уверен, что понял ваш вопрос, но если вы пишете:
mask_data[:3, :3] = 1
mask_data[3:, 3:] = 0
Это приведет к тому, что все значения данных маски, чьи индексы x и y будут меньше 3, будут равны 1, а все остальные будут равны 0