Как обрабатывать пропущенные значения в Pandas — isnull(), dropna(), fillna()?
isnull() обнаруживает пропуски (возвращает булеву маску), dropna() удаляет строки/столбцы с пропусками, fillna() заполняет их константой, статистикой или методом ffill/bfill.
Работа с пропущенными значениями в Pandas
Пропущенные значения (NaN, None, pd.NA) — одна из самых частых проблем в реальных данных. Pandas предоставляет три основных инструмента: обнаружение (isnull()/notnull()), удаление (dropna()) и заполнение (fillna()).
Обнаружение: isnull() и notnull()
isnull() (псевдоним: isna()) возвращает булеву маску той же формы, где True означает пропуск. notnull() — инверсия.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'name': ['Alice', 'Bob', None, 'Diana'],
'age': [25, np.nan, 30, 22],
'salary': [50000, 60000, np.nan, np.nan],
})
# булева маска
print(df.isnull())
# name age salary
# 0 False False False
# 1 False True False
# 2 True False True
# 3 False False True
# количество пропусков по столбцам
print(df.isnull().sum())
# name 1
# age 1
# salary 2
# процент пропусков
print(df.isnull().mean().round(2))
# name 0.25
# age 0.25
# salary 0.50
# строки, где хотя бы одно значение пропущено
print(df[df.isnull().any(axis=1)])
# строки без единого пропуска
print(df[df.notnull().all(axis=1)])
Удаление: dropna()
dropna() удаляет строки или столбцы с пропусками. Ключевые параметры: axis, how ('any' / 'all'), thresh (минимум непустых значений), subset (проверять только эти столбцы).
# удалить строки, где хотя бы один пропуск (по умолчанию)
df_clean = df.dropna()
print(df_clean)
# name age salary
# 0 Alice 25.0 50000.0
# удалить строки, где ВСЕ значения пропущены
df_no_all_nan = df.dropna(how='all')
# удалить строки с пропуском только в конкретных столбцах
df_need_age = df.dropna(subset=['age'])
# оставить строки, где непустых значений >= 2
df_thresh = df.dropna(thresh=2)
# удалить столбцы с любым пропуском
df_no_empty_cols = df.dropna(axis=1)
Заполнение: fillna()
fillna() заменяет пропуски константой, словарём значений или результатом метода интерполяции (method='ffill', 'bfill').
# заполнить все пропуски одним значением
df_zero = df.fillna(0)
# разные значения для разных столбцов
df_specific = df.fillna({'age': df['age'].median(), 'salary': df['salary'].mean()})
# forward fill — заполнить предыдущим значением (актуально для временных рядов)
ts = pd.DataFrame({'value': [1.0, np.nan, np.nan, 4.0, np.nan]})
ts_ffill = ts.fillna(method='ffill') # или ts['value'].ffill()
print(ts_ffill)
# 0 1.0
# 1 1.0
# 2 1.0
# 3 4.0
# 4 4.0
# backward fill
ts_bfill = ts.fillna(method='bfill') # или ts['value'].bfill()
# interpolate — линейная интерполяция (лучше для числовых рядов)
ts_interp = ts.interpolate(method='linear')
print(ts_interp)
# 0 1.000000
# 1 2.000000
# 2 3.000000
# 3 4.000000
# 4 4.000000
# ограничить количество последовательных заполнений
ts_limited = ts['value'].ffill(limit=1)
Проверка после обработки
result = df.fillna({'age': df['age'].median(), 'salary': df['salary'].mean()}).dropna()
assert result.isnull().sum().sum() == 0, "Остались пропуски!"
print(f"Итог: {len(result)} строк, пропусков нет")
Подводные камни
- inplace=True не работает в цепочках:
df.fillna(0, inplace=True)возвращаетNone, и если вы присвоите результат переменной — потеряете данные. Используйтеdf = df.fillna(0). - ffill/bfill не заполняет первый/последний NaN:
ffillне заполнит NaN в начале ряда (нет предыдущего значения),bfill— в конце. Комбинируйте оба метода:.ffill().bfill(). - dropna() с thresh считает непустые, не пустые:
thresh=2означает «оставить строки, где хотя бы 2 значения непустые», а не «удалить строки с более чем 2 пропусками» — легко перепутать. - Заполнение медианой/средним до сплита: при ML-пайплайне нельзя вычислять median/mean по всему датасету до train/test split — это data leakage. Считайте статистики только на train.
- isnull() не ловит строки 'nan', 'NULL', '': при чтении CSV грязные данные часто приходят как строка
'nan'или пустая строка. Используйтеpd.read_csv(..., na_values=['nan', 'NULL', '', 'N/A']). - method='ffill' устарел в fillna(): начиная с Pandas 2.2 параметр
method=вfillna()помечен как deprecated — используйтеdf.ffill()иdf.bfill()напрямую.
Common mistakes
- Объяснять
missing valuesтолько синтаксисом без shape, dtype, состояния или режима выполнения. - Игнорировать leakage, воспроизводимость, пустые входы и скрытые копии данных.
- Не проверять production-симптомы: latency, память, ретраи, дрейф качества и несовпадение версий.
What the interviewer is testing
- Может ли связать
missing valuesс реальным контрактом входов и выходов. - Упоминает ли тесты, метрики, reproducibility и диагностику ошибок.
- Видит ли различие между demo-кодом в ноутбуке и production-пайплайном.