Коротко
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.0posinf, neginfчем заменить +inf и −inf; None — самым большим / маленьким числом типаNoneaxisу nan-функций — как у обычных агрегацийNoneПримеры
temps = np.array([12.5, np.nan, 14.0, 11.0, np.nan]) # два дня без данныхprint(temps.sum()) # один NaN — и сумма тоже NaN
temps.mean()Вывод
nan np.float64(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, поэтому такая проверка молча ничего не находит.
print(np.nan == np.nan)
temps == np.nan # всегда False — так пропуски не найтиВывод
False array([False, False, False, False, False])
Среднее из одних NaN
Если в срезе нет ни одного значения, nan-функция возвращает NaN с предупреждением.
np.nanmean(np.array([np.nan, np.nan]))Вывод
RuntimeWarning: Mean of empty slice np.float64(nan)
NaN в целом массиве
days = np.array([1, 2, 3])
days[0] = np.nan # в целом массиве нет NaNОшибка
ValueError: cannot convert float NaN to integer
Для целых с пропусками есть маскированные массивы np.ma и nullable-типы pandas.