КПКейсПрактика
Все материалы
Продуктовая аналитикачеклистстарт

Очистка данных в pandas: пропуски, дубликаты и типы

Практический порядок очистки таблицы в pandas: найти дубликаты, обработать пропуски, привести типы и не удалить важные бизнес-сценарии.

КПКейсПрактика31 июля 2026 г.12 мин
Два аналитика очищают таблицу pandas от дублей и отделяют реальные пропуски от ошибок загрузки.

Очистка данных — это не “сделать таблицу красивой”. Нужно понять, какие строки являются дублями, что означает пропуск и какой тип должен быть у каждого поля. Если удалить всё подозрительное без правил, можно убрать реальные возвраты, повторные события или пользователей с неполным профилем.

Коротко

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

  • Не удаляй строки до того, как описал причину удаления.
  • Проверяй дубли по бизнес-ключу, а не по всей строке.
  • Пропуски в категориальном поле и в сумме денег требуют разных решений.
  • Приводи типы явно и считай число значений, которые не удалось преобразовать.

Опиши контракт учебной таблицы

Пусть в `orders` одна строка — один заказ. `order_id` обязателен и уникален, `created_at` должен быть датой, `revenue` — неотрицательным числом, а `channel` может быть неизвестным, но не пустой строкой. Такой контракт превращает спор о данных в набор проверок.

Пример контракта для orders
ПолеПравилоЧто делать при нарушении
order_idне NULL, уникаленостановить расчёт и проверить источник
created_atвалидная дата в известной timezoneвынести строки в отчёт ошибок
revenueчисло >= 0проверить возвраты и валюту, не ставить ноль автоматически
channelкатегория или unknownнормализовать регистр и пустые значения

Типы: строка с числом ещё не число

CSV часто отдаёт сумму как текст: `"1 250"`, `"1250,50"` или `"n/a"`. `pd.to_numeric` помогает привести значения, но после `errors="coerce"` нужно отдельно посмотреть, сколько строк превратилось в NaN. Иначе плохая запись растворится в среднем.

pythonПривести сумму и дату с контролем ошибок
before = orders['revenue'].isna().sum()
orders['revenue'] = (
    orders['revenue'].astype('string')
    .str.replace(' ', '', regex=False)
    .str.replace(',', '.', regex=False)
    .pipe(pd.to_numeric, errors='coerce')
)
after = orders['revenue'].isna().sum()
print('new missing revenue:', after - before)
orders['created_at'] = pd.to_datetime(orders['created_at'], errors='coerce', utc=True)

Дубликаты: сначала понять ключ

`drop_duplicates()` без subset сравнивает всю строку. Для заказа это может быть неправильно: одна и та же покупка могла получить обновлённый статус или комментарий. Если источник гарантирует одну строку на заказ, проверяй `order_id`; если это поток событий, ключом может быть user_id, event_name и occurred_at с допустимой точностью.

pythonНайти и сохранить повторные заказы
duplicates = orders.loc[orders.duplicated('order_id', keep=False)]
print('duplicate rows:', len(duplicates))

orders = (
    orders.sort_values('updated_at')
    .drop_duplicates('order_id', keep='last')
)
assert orders['order_id'].is_unique
Не каждый повтор — ошибка

В таблице статусов повторный order_id может быть историей изменений. В таблице фактов оплаты повтор может означать дубль загрузки. Решение зависит от зерна и бизнес-смысла, а не от самого названия метода.

Пропуски: unknown, zero и отдельный статус

Категориальный пропуск часто лучше превратить в явную группу `unknown`, чтобы он не исчез из группировки. Ноль подходит только тогда, когда отсутствие записи действительно означает отсутствие значения: например, скидка не применялась. Для неизвестной выручки ноль создаст ложное снижение среднего.

pythonОбработать пропуски по смыслу поля
orders['channel'] = orders['channel'].replace('', pd.NA).fillna('unknown')
orders['discount'] = orders['discount'].fillna(0)

invalid_revenue = orders['revenue'].isna() | orders['revenue'].lt(0)
quarantine = orders.loc[invalid_revenue].copy()
clean_orders = orders.loc[~invalid_revenue].copy()

Чеклист перед расчётом

Очищенная таблица должна быть не просто без пропусков. В финальном отчёте сохрани количество отброшенных строк, причины и контрольные числа. Так другой аналитик поймёт, почему выручка после очистки отличается от файла источника.

  • Сколько строк было в источнике и сколько осталось?
  • Сколько дублей найдено и по какому ключу?
  • Сколько значений не удалось привести к нужному типу?
  • Какие пропуски стали `unknown`, а какие — нулём?
  • Изменились ли сумма, количество заказов и диапазон дат?
Продолжить чтение
Вся библиотека