Булевы маски в NumPy — это массивы логических значений (dtype=bool), которые используются для выбора, фильтрации и изменения элементов массива без циклов. Это один из ключевых инструментов векторизации.

Идея простая:
каждый элемент маски соответствует элементу исходного массива и отвечает на вопрос — оставить (True) или отбросить (False).

Простейший пример:

import numpy as np
 
a = np.array([1, 5, 10, 15])
 
mask = a > 5
# mask = [False False  True  True]
 
a[mask]
# [10 15]

Здесь:
– сравнение a > 5 выполняется векторизованно
– результат — булев массив той же формы
– индексация по маске возвращает только элементы с True

Создание масок:

Маски почти всегда получаются из векторных сравнений:

a > 0
a == 10
(a >= 3) & (a <= 7)
(a < 0) | (a > 100)

Важно:
– используются побитовые операторы &, |, ~, а не and / or / not
– каждое условие берётся в скобки

Применение к многомерным массивам:

M = np.array([[1, -2, 3],
              [-4, 5, -6]])
 
mask = M > 0
M[mask]
# [1 3 5]

Форма маски должна совпадать с формой массива (или быть broadcast-совместимой).

Изменение элементов по маске:

a = np.array([1, -2, 3, -4])
a[a < 0] = 0
# [1 0 3 0]

Это типичный реальный паттерн: очистка, клиппинг, нормализация данных.

Маска + broadcasting:

X = np.array([[1, 2, 3],
              [4, 5, 6]])
 
mask = X.mean(axis=1) > 3
# mask.shape = (2,)
 
X[mask]
# [[4 5 6]]

Маска применяется по первой оси (строкам).

Что важно помнить на практике:

– индексация по маске всегда возвращает копию, а не view
– маски — это обычные ndarray, над ними можно делать &, |, ~
– булевы маски — основной способ условной логики без for

Коротко:
булева маска — это векторизованное условие, позволяющее выбирать и менять элементы массива декларативно, быстро и без циклов.