Очистка данных: Обработка пропусков, дубликатов, некорректных значений
Теперь, когда мы научились загружать данные из разных источников — будь то CSV, Excel или SQL — настало время сделать следующий шаг. Данные редко приходят в идеальном виде. Часто они содержат пропуски, дублируются или включают ошибки. Если не обработать эти проблемы, любой анализ, даже самый изящный, может привести к ложным выводам.
Представьте, что вы строите дом. Фундамент — это качество данных. Неважно, насколько красивы стены и крыша, если фундамент треснут — всё рухнет. Так и в аналитике: грязные данные = ложные решения.
В этой теме мы сосредоточимся на трёх ключевых типах проблем:
- Пропущенные значения (NaN)
- Дубликаты
- Некорректные данные (неверные типы, выбросы, форматы)
Мы разберём, как их обнаруживать и как принимать взвешенные решения по их обработке.
Диагностика: как понять, что данные "грязные"?
Прежде чем чистить, нужно понять, что именно требует чистки. Начнём с простого: загрузим датасет с данными о продажах.
import pandas as pd
# Загружаем данные (как вы уже умеете из темы "Чтение и запись данных")
df = pd.read_csv('sales_data_dirty.csv')
df.head()
Теперь посмотрим общую информацию:
df.info()
Этот метод покажет:
- Количество непустых значений в каждом столбце
- Типы данных
- Общее число строк
Если в каком-то столбце количество непустых значений меньше общего числа строк — значит, есть пропущенные значения.
Чтобы увидеть пропуски наглядно, используем:
df.isna().sum()
Это покажет количество NaN в каждом столбце.
💡 Совет: Для визуализации пропусков можно использовать библиотеку
missingno. Она строит тепловую карту, где пропуски видны как белые полосы. Это особенно полезно при работе с большими таблицами.
Обработка пропущенных значений
Пропущенные значения — одна из самых частых проблем. В Pandas они обозначаются как NaN (Not a Number).
Удалять или заполнять? Это зависит от:
- Объёма пропусков
- Типа данных
- Контекста
Вариант 1: Удаление строк или столбцов
Если пропусков меньше 5% и они распределены случайно — можно удалить строки:
df_clean = df.dropna(subset=['price']) # удаляем строки, где цена — NaN
Если в столбце больше 60% пропусков, и он не критичен — возможно, стоит удалить весь столбец:
df_clean = df.drop(columns=['promo_code']) # если коды акций почти везде пустые
⚠️ Осторожно: если вы удалите 40% строк, ваш анализ может потерять репрезентативность. Это как опросить только 60 человек из 100 — выборка перестаёт быть объективной.
Вариант 2: Заполнение значений
Более аккуратный подход — заполнить пропуски.
Для числовых данных:
- Среднее (
mean()) — если распределение близко к нормальному - Медиана (
median()) — если есть выбросы - Интерполяция — если данные временные
df['price'].fillna(df['price'].median(), inplace=True)
Для категориальных данных (например, region, category):
- Мода (
mode()) — самое частое значение - Или специальное значение:
"Unknown"
df['region'].fillna('Unknown', inplace=True)
📌 Правило: никогда не заполняйте категориальную переменную средним. Это бессмысленно и сломает анализ.
Удаление дубликатов
Дубликаты — это одинаковые строки, которые попали в данные дважды. Часто из-за ошибок выгрузки или дублирования действий.
Проверим:
df.duplicated().sum() # сколько полных дубликатов?
Удалим:
df_clean = df.drop_duplicates()
Но бывает частичное дублирование. Например, заказ с одинаковым order_id, но разный регистр в имени: "Иванов" и "иванов".
Для таких случаев — сначала нормализуем данные:
df['customer_name'] = df['customer_name'].str.strip().str.lower()
df_clean = df.drop_duplicates(subset=['order_id'])
Теперь дубликаты по order_id будут найдены корректно.
Исправление некорректных значений
Иногда данные "не горят", но явно ошибочны.
Проблема 1: Неверные типы данных
Дата хранится как строка? Нужно исправить:
df['order_date'] = pd.to_datetime(df['order_date'], errors='coerce')
errors='coerce' превратит некорректные даты (например, "2023-02-30") в NaN, чтобы их можно было обработать отдельно.
Проблема 2: Выбросы
Цена товара — 999 999 рублей? При средней в 5 000? Это выброс.
Его можно:
- Удалить
- Заменить на верхний предел (например, 99-й перцентиль)
- Исследовать: а вдруг это действительно редкий товар?
Для числовых столбцов полезно посмотреть статистику:
df['price'].describe()
Если max в 100 раз больше 75% — стоит проверить.
Проблема 3: Несоответствие форматов
Например, в столбце status значения: "Доставлен", "доставлен ", "в пути", "В Пути".
Нормализуем:
df['status'] = df['status'].str.strip().str.lower()
Теперь можно группировать и анализировать без ошибок.
Проверка результата и логирование
После очистки — обязательно проверьте:
print(f"Оригинальное количество строк: {len(df)}")
print(f"После очистки: {len(df_clean)}")
print(f"Пропуски осталось: {df_clean.isna().sum().sum()}")
Запишите, что вы сделали. Это важно для воспроизводимости:
🔹 Удалено 12 дубликатов
🔹 Пропуски вpriceзаполнены медианой (499 руб.)
🔹 Пропуски вregionзаменены на "Unknown"
🔹 Некорректные даты приведены к формату datetime, ошибки — в NaN
Такой лог поможет вам или коллеге понять, почему были приняты те или иные решения.
Почему это важно для карьеры?
На практике 80% времени аналитика уходит на подготовку данных. Работодатели это знают.
Умение работать с "грязными" данными — ключевой навык, который отличает Junior от Middle.
В российских компаниях особенно часто встречаются данные из устаревших систем, где:
- Даты в формате
DD.MM.YY - Пробелы в начале строк
- Дублирующиеся ID
Ваша способность быстро и аккуратно их обработать — прямой путь к доверию со стороны команды.
💼 Из практики: однажды я обнаружил, что в отчёте о прибыли 15% заказов были учтены дважды из-за дубликатов. После очистки — прибыль "снизилась", но зато цифра стала правдивой. Это спасло компанию от ошибочных инвестиций.
Что дальше?
Теперь, когда данные очищены, они готовы к анализу.
В следующей теме — Фильтрация, сортировка и выборка данных — мы научимся извлекать нужную информацию: например, "покажи топ-10 самых дорогих товаров за март".
Без очистки такие запросы могут выдать искажённые результаты. А теперь — у нас чистая основа.
Готовы превращать данные в инсайты? Поехали.