NumPyJuniorCoding

Как использовать булево индексирование для фильтрации массивов в NumPy?

Булева маска (массив bool той же формы) фильтрует элементы: x[x > 0]. Результат — копия, не view. 2D-маска даёт flat 1D результат; маска по строкам сохраняет 2D-форму. Используйте & | ~ вместо and/or/not.

Как работает булево индексирование

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

import numpy as np

x = np.array([10, -3, 7, -1, 5, -8, 2])

# Создаём булеву маску
mask = x > 0
print(mask)       # [ True False  True False  True False  True]
print(mask.dtype) # bool

# Применяем маску — получаем копию, не view
positive = x[mask]
print(positive)   # [10  7  5  2]
print(positive.shape)  # (4,) — 1D независимо от формы x

Составные условия

data = np.array([1.5, np.nan, 3.2, np.nan, 0.8, 4.1, -1.0])

# Операторы &, |, ~ (не and, or, not!)
valid = data[~np.isnan(data) & (data > 0)]
print(valid)  # [1.5 3.2 0.8 4.1]

# np.where — выбор из двух массивов по маске
clipped = np.where(data > 3, 3.0, data)  # cap значений на 3
print(clipped)  # [1.5 nan 3.  nan 0.8 3.  -1. ]

# np.where только с condition → эквивалент np.nonzero → возвращает индексы
indices = np.where(data > 3)
print(indices)  # (array([2, 5]),) — tuple из одного массива для 1D
print(data[indices])  # [3.2 4.1]

Булево индексирование на 2D массивах

matrix = np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
])

# Маска той же формы — результат всегда 1D
mask_2d = matrix > 4
print(matrix[mask_2d])  # [5 6 7 8 9] — flat array

# Маска по строкам (1D маска для 2D массива)
row_mask = matrix[:, 0] > 2  # первый столбец > 2
print(row_mask)               # [False  True  True]
filtered_rows = matrix[row_mask]
print(filtered_rows)  # [[4 5 6]
                      #  [7 8 9]]  — форма (2, 3) сохранена!

# Маска по столбцам
col_mask = np.array([True, False, True])
print(matrix[:, col_mask])  # столбцы 0 и 2

Изменение значений через булеву маску

temps = np.array([20.0, -999.0, 22.5, -999.0, 18.0])
sensor_error = -999.0

# Замена значений через индексирование (in-place)
temps[temps == sensor_error] = np.nan
print(temps)  # [20.  nan  22.5  nan  18. ]

# Clip отрицательных значений
losses = np.array([0.5, -0.1, 0.3, -0.2, 0.8])
losses[losses < 0] = 0.0  # ReLU-подобная операция
print(losses)  # [0.5 0.  0.3 0.  0.8]

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

  • Результат — копия, не view: x[x > 0] создаёт новый массив. Изменение результата не меняет x. Для in-place изменений используйте x[x > 0] = value (это срабатывает корректно).
  • & и | вместо and и or: Python-операторы and/or не работают с массивами — вызывают ValueError: The truth value of an array is ambiguous. Используйте побитовые &, |, ~ и обязательно расставляйте скобки: (a > 0) & (a < 10).
  • Маска другой формы — ошибка или неожиданный результат: при несовпадении shape NumPy пытается broadcast маску. Если не получается — IndexError. Всегда проверяйте mask.shape == arr.shape.
  • np.nan в условиях: np.nan > 0 возвращает False, np.nan == np.nan тоже False. Для проверки NaN используйте только np.isnan().
  • Производительность при повторном использовании: вычисление маски — отдельная аллокация. Если одна маска применяется многократно, сохраните её в переменную вместо пересчёта.
  • Индексирование типом int vs bool: arr[[True, False, True]] — булево, arr[[0, 2]] — fancy indexing, результаты эквивалентны, но поведение при broadcast отличается. Не смешивайте явно.

Common mistakes

  • Объяснять boolean indexing filtering только синтаксисом без shape, dtype, состояния или режима выполнения.
  • Игнорировать leakage, воспроизводимость, пустые входы и скрытые копии данных.
  • Не проверять production-симптомы: latency, память, ретраи, дрейф качества и несовпадение версий.

What the interviewer is testing

  • Может ли связать boolean indexing filtering с реальным контрактом входов и выходов.
  • Упоминает ли тесты, метрики, reproducibility и диагностику ошибок.
  • Видит ли различие между demo-кодом в ноутбуке и production-пайплайном.

Sources

Related topics