NumPy: вычисления и устройство массивов

NaN в числовых массивах: обнаружение и nan-устойчивые агрегаты

Содержание курса

Обнаружение NaN: np.isnan, np.any и np.all

Раз сравнение через == не работает, NumPy предоставляет специальную функцию — np.isnan. Она обходит каждый элемент массива и возвращает True ровно там, где стоит NaN:

import numpy as np

arr = np.array([1.0, np.nan, 3.0, np.nan, 5.0])
mask = np.isnan(arr)
print(mask)        # [False  True False  True False]
print(mask.shape)  # (5,)
print(mask.dtype)  # bool

Результат — булев массив той же формы, что входной. Его можно сразу использовать для индексации: arr[~mask] даст только элементы без NaN.

Есть ли в массиве хотя бы один NaN?

Просматривать булев массив глазами неудобно. Для быстрой проверки используют np.any и np.all.

np.any(mask) возвращает True, если в mask есть хотя бы один True — то есть хотя бы один NaN в исходном массиве:

print(np.any(np.isnan(arr)))  # True

np.all(mask) возвращает True только если все элементы mask равны True — то есть весь массив состоит из NaN:

print(np.all(np.isnan(arr)))  # False — есть и обычные числа

all_nan = np.array([np.nan, np.nan, np.nan])
print(np.all(np.isnan(all_nan)))  # True

Оба вызова принимают булев массив и возвращают скалярный bool — удобно для ветвления в коде:

if np.any(np.isnan(arr)):
    print("Массив содержит пропуски")

Комбинация np.isnan + np.any — стандартный способ проверить массив перед агрегацией. Если np.any(np.isnan(arr)) вернул True, нельзя просто взять np.sum или np.mean и получить осмысленный результат — почему именно, разберём в следующем разделе.