Статья Автор: Деникина Н.В., Деникин А.В.

Пустота со смыслом

Пустота со смыслом

Пустая ячейка выглядит как отсутствие информации. Но для аналитика это уже факт: значение почему-то не было записано. Причины могут быть совершенно разными. Псевдоним персонажа неизвестен. Измерение не проводили. Источник никогда не собирал это поле. Значение потерялось при переносе файла. Во всех случаях pandas покажет нам один и тот же NaN, хотя решения могут понадобиться разные.

В ячейке нет значения Почему? Значение неизвестно оставить NaN Без значения объект не описать возможно удалить строку Можно разумно оценить значение импутация с обоснованием Пропуск имеет самостоятельный смысл например: Unknown Один и тот же NaN может требовать разных решений

Поэтому вопрос «чем заполнить пропуск?» появляется слишком рано. Сначала полезнее спросить: почему его нет и нужен ли этот признак для нашей задачи?
 

Иногда пустота прячется

В CSV отсутствие значения не обязано выглядеть как настоящий NaN. Встречаются пустые строки, -, N/A, unknown. Для человека они означают примерно одно и то же, а для программы могут быть обычными строками.

print(df["alias"].value_counts(dropna=False))
print(df["universe"].unique())

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

Где пропуски встречаются — не менее важно, чем сколько их

Допустим, в некотором проекте данные собираются из нескольких систем. В одной из них признак пропущен в 35% строк, а во всех остальных — примерно в 2%. Общая медиана не объяснит, почему возникла такая разница. Более того, если сразу заполнить все пропуски, след проблемы почти исчезнет.

missing_by_source = (
    df.groupby("source_system")["value"]
      .apply(lambda s: s.isna().mean())
)

print(missing_by_source)

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


В одном источнике пропущено 35% значений признака, а в остальных — около 2%. Какой вопрос стоит задать прежде, чем заполнять пропуски?


Заполнять — значит делать предположение

Если значение действительно нужно восстановить, часто вспоминают среднее и медиану. Но это не две равноценные кнопки. Посмотрим на costume_cost в нашей таблице: медианная стоимость около 271 тысячи, средняя — почти 39,9 миллиона. Причина в нескольких очень дорогих костюмах, которые сильно тянут среднее вверх.

costume_cost в реальном датасете Медиана ≈ 271 тыс. типичный центр устойчив к редким гигантским значениям Среднее ≈ 39,9 млн его заметно тянут вверх редкие очень дорогие значения Максимум > 490 млн поэтому среднее здесь не равно «обычной стоимости» Несколько очень больших значений почти не меняют медиану, но сильно поднимают среднее

В таком распределении медиана устойчивее к экстремальным значениям. Это делает её разумным кандидатом для некоторых задач, но не превращает в «истинную стоимость неизвестного костюма». Любое заполнение — это модельное предположение, и его последствия нужно понимать.

Иногда честнее оставить NaN. Иногда отсутствие значения само по себе образует отдельную категорию вроде Unknown. Иногда строку действительно приходится удалить — например, если без ключевого признака объект нельзя использовать в конкретном анализе. Но перед удалением стоит посчитать цену: сколько строк исчезнет и не относится ли большая часть из них к одной группе.

Цель предобработки поэтому не в том, чтобы получить красивый ноль в isna().sum(). Цель — сделать отсутствие данных явным и выбрать решение, которое соответствует их происхождению.


Какие утверждения верны?


Следующая проблема внешне противоположна: значения не пропали, а наоборот, как будто повторились. Но и здесь слово «дубликат» оказывается не таким простым, как кажется.

Перейти к лаборатории «Спасти базу супергероев» →

Печать