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

NaN и бесконечности

Как хранить пропуски в массиве, находить их и считать суммы и средние без них.

Нужно знать:Базовые агрегацииБулевы маски

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

Коротко

  • np.nan (not a number) — стандартная метка пропуска в дробных массивах; np.inf — бесконечность.
  • NaN «заражает» вычисления: сумма, среднее, максимум с NaN дают NaN.
  • Функции nansum, nanmean, nanmax, nanmedian, nanstd… пропускают NaN.
  • NaN не равен ничему, даже себе. Искать пропуски — только через np.isnan.
  • NaN бывает только в float-массивах; в целых его хранить нельзя.

Синтаксис

np.isnan(a), np.isinf(a), np.isfinite(a)   # маски
np.nansum(a), np.nanmean(a), np.nanmax(a)  # без учёта NaN
np.nan_to_num(a, nan=0.0, posinf=None, neginf=None)
a[~np.isnan(a)]                            # только известные значения

Параметры

ПараметрЧто делаетПо умолчанию
nanчем заменить NaN в nan_to_num0.0
posinf, neginfчем заменить +inf и −inf; None — самым большим / маленьким числом типаNone
axisу nan-функций — как у обычных агрегацийNone

Примеры

Данные для примеровиспользуются во всех примерах ниже
temps = np.array([12.5, np.nan, 14.0, 11.0, np.nan])   # два дня без данных
NaN в сумме и среднем
print(temps.sum())            # один NaN — и сумма тоже NaN
temps.mean()
Вывод
nan
np.float64(nan)
Агрегации без NaN
print(np.nansum(temps))
print(np.nanmean(temps))
np.nanmax(temps)
Вывод
37.5
12.5
np.float64(14.0)
Найти и отбросить пропуски
mask = np.isnan(temps)
print(mask)
print(mask.sum())             # сколько пропусков
temps[~mask]                  # только известные значения
Вывод
[False  True False False  True]
2
array([12.5, 14. , 11. ])
Заполнить пропуски
print(np.nan_to_num(temps))                        # NaN → 0
np.where(np.isnan(temps), np.nanmean(temps), temps)   # NaN → среднее
Вывод
[12.5  0.  14.  11.   0. ]
array([12.5, 12.5, 14. , 11. , 12.5])
Бесконечности
x = np.array([np.inf, -np.inf, 5.0])
print(np.isinf(x), np.isfinite(x))
print(x - x)                  # inf − inf = nan
x.max()
Вывод
[ True  True False] [False False  True]
RuntimeWarning: invalid value encountered in subtract
[nan nan  0.]
np.float64(inf)

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

Сравнение с np.nan

a == np.nan всегда даёт False, поэтому такая проверка молча ничего не находит.

Поиск NaN через ==
print(np.nan == np.nan)
temps == np.nan               # всегда False — так пропуски не найти
Вывод
False
array([False, False, False, False, False])

Среднее из одних NaN

Если в срезе нет ни одного значения, nan-функция возвращает NaN с предупреждением.

nanmean без значений
np.nanmean(np.array([np.nan, np.nan]))
Вывод
RuntimeWarning: Mean of empty slice
np.float64(nan)

NaN в целом массиве

Запись NaN в int-массивошибка: ValueError
days = np.array([1, 2, 3])
days[0] = np.nan              # в целом массиве нет NaN
Ошибка
ValueError: cannot convert float NaN to integer

Для целых с пропусками есть маскированные массивы np.ma и nullable-типы pandas.