← Назад к вопросам

Как обрабатывать пропущенные значения в данных?

1.6 Junior🔥 261 комментариев
#Pandas и обработка данных

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Обработка пропущенных значений (Missing Data)

Пропущенное значение — это отсутствие данных в какой-то ячейке таблицы. В Python/Pandas обозначается как NaN, None или NA. Это одна из самых частых задач при подготовке данных.

Виды пропусков (MCAR, MAR, MNAR)

1. MCAR (Missing Completely At Random)

Определение: вероятность пропуска не зависит ни от наблюдаемых, ни от ненаблюдаемых переменных. Полностью случайно.

Пример: из-за сбоя датчика потеряны некоторые измерения

Как обработать: любой метод работает хорошо (удаление, импутация, модели).

2. MAR (Missing At Random)

Определение: вероятность пропуска зависит от наблюдаемых переменных, но не от самого пропущенного значения.

Пример: люди с высокой зарплатой менее охотно её указывают.
Пропуск зарплаты зависит от: был ли вопрос, откуда человек узнал об опросе,
но не от самой зарплаты напрямую.

Как обработать: метод на основе всех доступных переменных (например, multiple imputation).

3. MNAR (Missing Not At Random)

Определение: вероятность пропуска зависит от самого пропущенного значения. Систематическое смещение.

Пример: люди с низким доходом не указывают зарплату
(пропуск зависит от величины дохода)

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

Первая диагностика пропусков

import pandas as pd
import numpy as np

df = pd.read_csv('data.csv')

# Подсчёт пропусков
print(df.isnull().sum())

# Процент пропусков по столбцам
print((df.isnull().sum() / len(df) * 100).round(2))

# Визуализация пропусков
import matplotlib.pyplot as plt
df.isnull().sum().plot(kind='barh')
plt.xlabel('Количество пропусков')
plt.show()

# Матрица пропусков (для понимания корреляции)
import seaborn as sns
sns.heatmap(df.isnull(), cbar=True, yticklabels=False)
plt.show()

Методы обработки пропусков

1. Удаление (Deletion)

Полное удаление строк с пропусками:

# Удалить строки с любыми пропусками
df_clean = df.dropna()

# Удалить строки с пропусками в конкретном столбце
df_clean = df.dropna(subset=['age', 'salary'])

# Удалить столбцы, в которых > 50% пропусков
df_clean = df.dropna(thresh=len(df) * 0.5, axis=1)

Когда использовать:

  • Пропусков мало (< 5%)
  • Тип: MCAR
  • Размер выборки позволяет потерю строк

Минусы:

  • Потеря информации
  • Смещение, если пропуски не MCAR

2. Заполнение константой (Forward/Backward Fill)

# Заполнить последним известным значением (временные ряды)
df['price'] = df['price'].fillna(method='ffill')  # forward fill
df['price'] = df['price'].fillna(method='bfill')  # backward fill

# Заполнить средним
df['age'] = df['age'].fillna(df['age'].mean())

# Заполнить медианой (робастнее при выбросах)
df['salary'] = df['salary'].fillna(df['salary'].median())

# Заполнить модой (для категориальных)
df['city'] = df['city'].fillna(df['city'].mode()[0])

# Заполнить нулём (для признаков, где 0 имеет смысл)
df['purchases'] = df['purchases'].fillna(0)

Минусы:

  • Ненеестественно — искусственно снижается дисперсия
  • Модели могут переучиться на эту закономерность

3. Интерполяция (Interpolation)

Для временных рядов — предположить промежуточное значение:

# Линейная интерполяция
df['temperature'] = df['temperature'].interpolate(method='linear')

# Полиномиальная
df['temperature'] = df['temperature'].interpolate(method='polynomial', order=2)

# На основе индекса (для временных рядов)
df['value'] = df['value'].interpolate(method='index')

4. Простая импутация (Simple Imputation)

K-NN Imputer: заполнить значением K ближайших соседей

from sklearn.impute import KNNImputer

imputer = KNNImputer(n_neighbors=5)
df_imputed = pd.DataFrame(
    imputer.fit_transform(df),
    columns=df.columns
)

Iterative Imputer (MICE): несколько итераций с разными признаками

from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer

imputer = IterativeImputer(random_state=42, max_iter=10)
df_imputed = pd.DataFrame(
    imputer.fit_transform(df),
    columns=df.columns
)

5. Multiple Imputation (множественная импутация)

Заполнить несколько вариантов и усреднить результаты (для неопределённости):

from sklearn.impute import SimpleImputer
import numpy as np

n_imputations = 5
df_imputed_list = []

for i in range(n_imputations):
    imputer = SimpleImputer(strategy='mean')
    df_temp = pd.DataFrame(
        imputer.fit_transform(df),
        columns=df.columns
    )
    df_imputed_list.append(df_temp)

# Усреднить предсказания всех вариантов
df_final = pd.concat(df_imputed_list).groupby(level=0).mean()

6. Моделирование (Prediction-based Imputation)

Предсказать пропущенные значения через модель:

from sklearn.linear_model import LinearRegression

# Разделить на данные с известным и неизвестным возрастом
df_known = df[df['age'].notna()]
df_unknown = df[df['age'].isna()]

# Обучить модель
model = LinearRegression()
model.fit(df_known[['income', 'education']], df_known['age'])

# Предсказать
df.loc[df['age'].isna(), 'age'] = model.predict(
    df_unknown[['income', 'education']]
)

Специальные техники

Создание флага пропуска

# Добавить столбец-индикатор (может быть информативно для модели)
df['age_missing'] = df['age'].isnull().astype(int)

Group-based Imputation

# Заполнить средним по группе (например, по возрастной группе)
df['salary'] = df.groupby('age_group')['salary'].transform(
    lambda x: x.fillna(x.mean())
)

Выбор метода: рекомендации

СитуацияМетодПримечание
< 5% пропусков, MCARУдалениеПростой и эффективный
Временной рядИнтерполяцияЕстественно для TS
КатегориальныеМода или отдельная категория'Missing' как отдельный класс
Структурные пропускиНулевое заполнениеage_child = 0 (не применимо)
Сложные зависимостиKNN или IterativeImputerУчитывает корреляции
Production модельMultiple ImputationЧестнее про неопределённость

Антипаттерны

# ❌ ПЛОХО: заполнить всё средним
df.fillna(df.mean())

# ❌ ПЛОХО: удалить все строки с пропусками без анализа
df.dropna()

# ❌ ПЛОХО: проигнорировать пропуски
# ✅ ХОРОШО: явно разобраться с механизмом пропусков

Ключевые выводы

  • Сначала анализируй: определи тип пропусков (MCAR/MAR/MNAR)
  • Для малых пропусков: удаление часто работает
  • Для зависимостей: KNN или IterativeImputer
  • Для временных рядов: интерполяция
  • Для категорий: мода или отдельная категория
  • На production: multiple imputation честнее про неопределённость
Как обрабатывать пропущенные значения в данных? | PrepBro