Нашли ошибку?
среднийNumPy 2.5.3

Булевы маски

Отобрать или изменить элементы по условию — без циклов и if.

Нужно знать:Индексация и срезыСравнение массивов

Содержание статьи

Коротко

  • Сравнение массива даёт маску — массив True/False той же формы: temps > 5.
  • a[маска] возвращает элементы, где маска True. Результат — одномерная копия.
  • Условия объединяют через & (и), | (или), ~ (не), каждое условие — в скобках. Слова and, or, not с массивами не работают.
  • a[маска] = значение меняет только выбранные элементы.
  • маска.sum() — сколько True, маска.mean() — их доля; any() / all() — есть ли хоть один / все ли.

Синтаксис

mask = a > 0
a[mask]                      # или сразу a[a > 0]
a[(a > 0) & (a < 10)]        # и
a[(a < 0) | (a > 10)]        # или
a[~mask]                     # не
a[a < 0] = 0                 # запись по маске
mask.sum(), mask.any(), mask.all()

Примеры

Данные для примеровиспользуются во всех примерах ниже
# дневная температура за две недели
temps = np.array([3, -2, 5, 8, -1, 0, 12, 15, 9, -4, 6, 11, 14, 2])
Маска и отбор
warm = temps > 5
print(warm)
temps[warm]              # только элементы, где маска True
Вывод
[False False False  True False False  True  True  True False  True  True
  True False]
array([ 8, 12, 15,  9,  6, 11, 14])
Несколько условий
print(temps[(temps > 0) & (temps < 10)])   # и
print(temps[(temps < 0) | (temps > 12)])   # или
temps[~(temps > 5)]                        # не
Вывод
[3 5 8 9 6 2]
[-2 -1 15 -4 14]
array([ 3, -2,  5, -1,  0, -4,  2])
Замена по условию
fixed = temps.copy()
fixed[fixed < 0] = 0     # отрицательные — в ноль
fixed
Вывод
array([ 3,  0,  5,  8,  0,  0, 12, 15,  9,  0,  6, 11, 14,  2])

a[a < 0] = 0 меняет массив на месте. Если нужно получить новый массив, не трогая старый, используйте np.where или np.clip.

Сколько элементов подходит
print((temps < 0).sum())          # True считается как 1
print(np.count_nonzero(temps > 10))
print((temps > 10).mean())        # доля дней
print((temps > 20).any(), (temps > -10).all())
Вывод
3
4
0.2857142857142857
False True
Маска двумерного массива
grid = np.array([[1, -2, 3],
                 [-4, 5, -6]])
grid[grid > 0]           # результат всегда одномерный
Вывод
array([1, 3, 5])

Подводные камни

and / or вместо & / |

Python пытается превратить весь массив в одно True или False и не может.

and с массивамиошибка: ValueError
temps[(temps > 0) and (temps < 10)]
Ошибка
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Условия без скобок

У & и | приоритет выше, чем у > и <: a > 0 & a < 10 читается как a > (0 & a) < 10. Скобки вокруг каждого условия обязательны.

Без скобокошибка: ValueError
temps[temps > 0 & temps < 10]     # & выполняется раньше сравнений
Ошибка
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()