Привет, Хабр! Меня зовут Руслан Каллагов, я системный аналитик в Лаборатории Globus — партнёре Нетологии по стажировкам на курсах ИТ-профессий. Уже 4,5 года я работаю в проектировании программного обеспечения и верю в инженерный подход к подготовке данных. Специально для хабровчан собрал практическое руководство по подготовке, очистке и предобработке данных для анализа и машинного обучения. В нём объясняю ключевые этапы подготовки данных, показываю примеры кода, даю чек-листы и алгоритмы действий.

Я считаю, что подготовка данных — самый недооценённый этап аналитики. Его не видно в демо, за него редко благодарят, и почти никогда не закладывают время. Но именно здесь решается главный вопрос проекта: можно ли этим данным доверять вообще.

TL;DR для тех, кто не хочет долго читать
  • Данные почти всегда «грязные».

  • Подготовка = pipeline, а не набор действий.

  • Очистка ≠ предобработка.

  • Масштабирование критично для моделей.

  • Если процесс не автоматизирован — это долг.

По данным ежегодных опросов Anaconda (2023, 2024), подготовка и очистка данных остаются наиболее времязатратными задачами дата-специалистов — вне зависимости от того, насколько автоматизирован их рабочий процесс. Исторически оценки варьировались от 45 до 80% рабочего времени (Anaconda 2020, CrowdFlower 2016), и хотя инструменты за последние годы стали лучше, задача никуда не исчезла.


Какие термины используются в статье:

  • очистка данных (data cleansing) — исправление ошибок (дубликатов, пропусков, выбросов, некорректных значений);

  • предобработка данных (data preprocessing, wrangling) — преобразование (типы, масштабирование, кодирование, признаки);

  • подготовка данных (data preparation) — общий процесс (включает исследование → очистку → преобразование → проверку).

Очистка отвечает на вопрос: «Что в данных сломано».
Предобработка: «Как привести данные в рабочий вид».
Подготовка: «Как пройти путь от сырого набора до данных, которым можно доверять».

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


Почему данные почти всегда «грязные»

В реальных проектах данные редко бывают аккуратными. Они содержат пропуски, дубликаты, ошибки формата и противоречия — такие данные принято называть «грязными» (dirty data). Это не исключение, а правило: данные поступают из разных систем, вводятся вручную, мигрируют между платформами.

Пример «грязных» данных:

| user_id | age | salary | signup_date | department |
| ------- | --- | ------ | ----------- | ---------- |
| 101     | 25  | 50000  | 2023-01-10  | Sales      |
| 102     | NaN | 60000  | 10.01.2023  | Marketing  |
| 103     | -5  | 70000  | 2023/01/12  | IT         |
| 101     | 25  | 50000  | 2023-01-10  | Sales      |
| 104     | 200 | NULL   | 2023-01-15  | HR         |

Типичные проблемы «грязных» данных: пропуски (NaN, NULL), дубликаты, выбросы, разные форматы, логические ошибки. Ещё пример:

import pandas as pd

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

df.info()
df.isna().sum()
df.duplicated().sum()
df.describe()

Проблема особенно актуальна для российского рынка: уровень цифровой зрелости российских организаций на конец 2025 года составлял лишь 45%, а значит, большинство компаний ещё не выстроили системное управление качеством данных. Даже в зрелых организациях проекты ИИ и аналитическая отчётность нередко опираются на грязные и разрозненные данные, что снижает доверие и к моделям, и к аналитике.

Этапы подготовки данных: от хаоса к системе

Чтобы не работать на ощупь, подготовку данных нужно выстраивать как пайплайн: исследование → очистка → объединение → предобработка → валидация.

1. Исследование и профилирование данных

На этом этапе мы ничего не исправляем — мы понимаем данные.

Что делаем

  1. Смотрим структуру.

  2. Проверяем типы.

  3. Считаем пропуски.

  4. Анализируем распределения.

  5. Ищем аномалии.

Пример:

df.info()
df.isna().sum()
df.describe(include="all")

Критерии успеха

Вы можете ответить:

  • какие поля проблемные;

  • где риски;

  • какие шаги очистки нужны.

2. Очистка данных

Теперь убираем ошибки.

Что делаем

Дубликаты:

df = df.drop_duplicates()

Пропуски:

df["salary"] = df["salary"].fillna(df["salary"].median())

Ошибки и выбросы:

df = df[df["age"].between(0, 120)]

Критерии успеха

Что имеем в итоге:

  • данные логически корректны;

  • нет критичных аномалий;

  • структура не разрушена.

3. Объединение данных

Если источников несколько, их нужно согласовать.

df = users.merge(orders, on="user_id", how="left")

Риски

  • Потеря строк.

  • Дубликаты после join.

  • Несовпадение ключей.

Критерии успеха

  • Данные согласованы.

  • Ключи валидны.

  • Нет размножения строк.

4. Предобработка и преобразование данных

Теперь приводим данные в рабочий вид.

Что делаем

  • Преобразуем типы.

  • Кодируем категории.

  • Создаём признаки.

  • Масштабируем числовые данные.

Важный этап: масштабирование признаков

Масштабирование нужно, чтобы признаки были сопоставимы.

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

Основные методы

StandardScaler: центрирует данные, стандартное отклонение = 1.

MinMaxScaler: приводит к диапазону [0, 1].

RobustScaler: устойчив к выбросам.

Пример:

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
df[["age", "salary"]] = scaler.fit_transform(df[["age", "salary"]])

Критерии успеха

  • Признаки сопоставимы.

  • Модель обучается стабильнее.

  • Нет перекоса из-за масштаба.

5. Проверка качества данных

Финальный контроль. Пример:

assert df["user_id"].notna().all()
assert df["age"].between(-5, 5).all()

Критерии успеха

  • Данные проходят проверки.

  • Пайплайн воспроизводим.

  • Можно использовать в проде.

Практический пример: полный цикл

import pandas as pd
from sklearn.preprocessing import StandardScaler

df = pd.read_csv("users.csv")

# 1. Очистка
df = df.drop_duplicates()
df["salary"] = df["salary"].fillna(df["salary"].median())
df = df[df["age"].between(0, 120)]

# 2. Преобразование
df["signup_date"] = pd.to_datetime(df["signup_date"], errors="coerce")

# 3. Масштабирование
scaler = StandardScaler()
df[["age", "salary"]] = scaler.fit_transform(df[["age", "salary"]])

# 4. Валидация
assert df["user_id"].notna().all()

6. Приведение типов и форматов

На этом этапе данные приводят в вид, с которым можно работать дальше:

  • строки → числа;

  • даты → datetime;

  • единицы измерения → к одному стандарту.

Если типы данных некорректны, дальше почти гарантированы баги от неправильных расчётов до падения пайплайнов.

7. Кодирование и масштабирование признаков

Для моделей данные почти всегда нужно преобразовать:

  • категориальные признаки → закодировать;

  • числовые → масштабировать.

Пример:

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
df[['age', 'salary']] = scaler.fit_transform(df[['age', 'salary']])

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

8. Проверка качества после очистки

После всех преобразований нужно задать себе простой вопрос: «Стали ли данные лучше, чем были?»

Минимум, что стоит проверить:

  • не потеряли ли вы важные сегменты;

  • не изменились ли распределения радикально;

  • не появились ли новые аномалии.

Если вы не смотрите на данные после очистки, вы работаете вслепую.

Инструменты для подготовки данных: что использовать и как именно

На этом этапе обычно возникает вопрос: «Окей, понятно, что делать. А какие инструменты для этого использовать?».

Ниже — практический минимум, который закрывает большинство задач.

pandas — базовый инструмент для очистки и анализа структуры данных

Если данные табличные (CSV, Excel, выгрузки из БД), то в большинстве проектов работа начинается именно здесь.

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

  • первичная загрузка данных;

  • поиск дубликатов и пропусков;

  • базовая очистка и трансформации;

  • быстрый анализ структуры.

Как применять на практике:

import pandas as pd

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

# Общая информация о данных
df.info()

# Количество пропусков по столбцам
df.isna().sum()

# Удаление дубликатов
df = df.drop_duplicates()

# Приведение типов
df['created_at'] = pd.to_datetime(df['created_at'])

Практический совет: если вы не запускали info() и isna().sum(), вы ещё не начинали подготовку данных.

Pandera — валидация данных по правилам (как тесты, только для данных)

Pandera позволяет описывать ожидания от данных в виде схем: типы, диапазоны, обязательные поля. Это особенно полезно, когда данные приходят регулярно.

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

  • данные обновляются ежедневно или по расписанию;

  • важно ловить ошибки до анализа;

  • нужно формализовать требования к данным.

Как применять на практике:

import pandera as pa
from pandera import Column, DataFrameSchema

schema = DataFrameSchema({
   "user_id": Column(int, nullable=False),
   "age": Column(int, pa.Check.between(0, 120)),
   "salary": Column(float, nullable=True),
})

schema.validate(df)

Если данные не соответствуют ожиданиям, вы получите явное сообщение об ошибке — а не анализ, который незаметно даёт неверный результат.

Great Expectations — контроль качества данных на уровне пайплайна

Инструмент для описания ожиданий к данным и автоматической проверки качества.

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

  • ETL/ELT-пайплайны;

  • аналитика в продакшене;

  • нужно логировать проблемы с данными.

Типичные проверки:

  • столбец не должен быть пустым;

  • значения в диапазоне;

  • уникальность ключей;

  • допустимые категории.

Идея использования: данные пришли → прогнали проверки → только после этого пошли в аналитику или модель.

scikit-learn — предобработка признаков для моделей

Для машинного обучения подготовка данных почти всегда включает кодирование и масштабирование.

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

  • обучение моделей;

  • чувствительные к масштабу алгоритмы;

  • пайплайны ML.

Как применять на практике:

from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer

preprocessor = ColumnTransformer(
   transformers=[
       ('num', StandardScaler(), ['age', 'salary']),
       ('cat', OneHotEncoder(handle_unknown='ignore'), ['department'])
   ]
)

X_prepared = preprocessor.fit_transform(df)

Важно: если предобработка не включена в пайплайн модели, вы почти гарантированно получите баг при переобучении или инференсе (применении обученной модели).

SQL — очистка данных как можно раньше

Если данные хранятся в БД, часть очистки лучше делать сразу на уровне SQL.

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

  • большие объёмы данных;

  • агрегации;

  • фильтрация мусора на входе.

Как применять на практике:

SELECT DISTINCT
   user_id,
   created_at,
   salary
FROM users
WHERE salary IS NOT NULL
 AND salary >= 0;

Чем раньше вы отсекаете мусор, тем дешевле и надёжнее аналитика.

Jupyter и Google Colab — интерактивная проверка и отладка

Jupyter и Google Colab — инструменты не для продакшена, но хорошо подходят для исследования данных.

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

  • исследовательская аналитика;

  • проверка гипотез;

  • визуальный контроль очистки.

Практика «очистил → сразу посмотрел график» экономит часы отладки.


Краткий чек-лист выбора инструмента

  • Нужно быстро посмотреть данные → pandas + Jupyter.

  • Нужно формализовать правила → Pandera.

  • Нужно следить за качеством в продакшене → Great Expectations.

  • Готовите данные для модели → scikit-learn.

  • Большие объёмы → SQL как можно раньше.


Ручная vs. автоматизированная предобработка: как это выглядит в реальной работе

На практике подготовка данных почти всегда проходит в два этапа:

  1. ручная предобработка (exploration mode);

  2. автоматизированная предобработка (production mode).

Это не два разных подхода. Это две стадии одного процесса.

Ручная предобработка: этап исследования

На старте вы почти всегда работаете вручную — в Jupyter Notebook или аналоге. Цель этапа — не почистить всё идеально, а:

  • понять структуру данных;

  • найти типичные ошибки;

  • протестировать гипотезы очистки;

  • выбрать стратегии обработки.

Пример — тот же «грязный» датасет пользователей:

import pandas as pd

df = pd.read_csv("users.csv")

# Смотрим структуру
df.info()

# Проверяем пропуски
df.isna().sum()

# Ищем дубликаты
df.duplicated().sum()

# Смотрим аномалии
df[df["age"] < 0]
df[df["age"] > 120]
Дальше — пробуем разные стратегии:
# Вариант 1: удалить дубликаты
df = df.drop_duplicates()

# Вариант 2: заполнить пропуски
df["salary"] = df["salary"].fillna(df["salary"].median())

# Вариант 3: убрать выбросы
df = df[df["age"].between(0, 120)]

На этом этапе допустимы эксперименты, временные решения, ручные правки.

Ключевая цель: понять, какие правила очистки вообще нужны.

Практический пример: пошаговая предобработка одного датасета

Соберём всё в единый процесс:

import pandas as pd
from sklearn.preprocessing import StandardScaler

df = pd.read_csv("users.csv")

Шаг 1. Первичный анализ

df.info()
df.isna().sum()
df.duplicated().sum()

Что выясняем:

  • есть пропуски в salary;

  • есть дубликаты;

  • есть некорректные значения возраста.

Шаг 2. Очистка

# Удаляем дубликаты
df = df.drop_duplicates()
# Заполняем пропуски
df["salary"] = df["salary"].fillna(df["salary"].median())
# Фильтруем выбросы
df = df[df["age"].between(0, 120)]

Шаг 3. Приведение форматов

df["signup_date"] = pd.to_datetime(df["signup_date"], errors="coerce")Шаг 4. Масштабирование

Шаг 4. Масштабирование

scaler = StandardScaler()
df[["age", "salary"]] = scaler.fit_transform(df[["age", "salary"]])

Шаг 5. Проверка результата

assert df["user_id"].notna().all()

На этом этапе у вас уже есть рабочая логика подготовки данных. Но пока она существует только в виде набора ручных действий.

Автоматизированная предобработка: переход в продакшен

Ручной режим перестаёт работать, как только наступает одно из условий:

  • данные обновляются регулярно;

  • появляется модель или отчёт;

  • процесс нужно повторять.

Теперь задача — сделать процесс воспроизводимым.

Как выглядит автоматизация

Те же шаги оформляются в функцию:

def preprocess_users(df: pd.DataFrame) -> pd.DataFrame:
   df = df.copy()

   # Очистка
   df = df.drop_duplicates()
   df["salary"] = df["salary"].fillna(df["salary"].median())
   df = df[df["age"].between(0, 120)]
  
   # Преобразование
   df["signup_date"] = pd.to_datetime(df["signup_date"], errors="coerce")
  
   return df

Теперь код можно переиспользовать, результат воспроизводим, ошибки легче отлаживать.

Следующий уровень: полноценный пайплайн

Пример:

def full_pipeline(df: pd.DataFrame) -> pd.DataFrame:
   df = preprocess_users(df)
  
   from sklearn.preprocessing import StandardScaler
   scaler = StandardScaler()
  
   df[["age", "salary"]] = scaler.fit_transform(df[["age", "salary"]])
  
   return df

Как понять, что пора автоматизировать

Автоматизация — уже не опция, а необходимость, если выполняется хотя бы одно из условий:

  • данные обновляются регулярно;

  • вы повторяете одни и те же шаги;

  • результат влияет на бизнес-решения;

  • есть модель или отчёт в проде.

Ручная предобработка отвечает на вопрос: «Что нужно сделать с данными?»

Автоматизированная — на вопрос: «Как делать это стабильно каждый раз?»

Если у вас есть только первый этап — у вас прототип. Если есть оба — у вас система.

Частые ошибки при подготовке данных

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

1. Удаляем строки без понимания последствий

В чём ошибка: строки с пропусками или аномалиями удаляют автоматически просто потому, что так проще.

Чем это опасно: можно случайно выкинуть важный сегмент данных и исказить картину.

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

2. Заполняем пропуски по умолчанию, не глядя на распределение

В чём ошибка: импутация делается механически — средним, медианой или константой — без проверки, подходит ли это для конкретного признака.

Чем это опасно: можно сместить распределение и ухудшить качество анализа или модели.

Что делать вместо этого: сначала посмотреть распределение признака и понять, насколько выбранный способ заполнения искажает данные.

3. Игнорируем логические противоречия

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

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

Что делать вместо этого: добавлять бизнес-валидацию — проверять не только типы и диапазоны, но и смысловые ограничения.

4. Работаем «на глаз» без повторяемого процесса

В чём ошибка: очистка делается вручную, по месту, без скриптов и без фиксированной логики.

Чем это опасно: процесс нельзя воспроизвести, а значит, нельзя нормально обновить данные или отладить результат.

Что делать вместо этого: оформлять подготовку данных в виде кода или пайплайна, чтобы любой шаг можно было повторить.

5. Не сохраняем исходную версию данных

В чём ошибка: работа идёт только с одной копией датасета.

Чем это опасно: если что-то пошло не так, откатиться уже некуда.

Что делать вместо этого: всегда хранить raw-версию отдельно и вести версии после каждого этапа подготовки.

6. Не документируем, что именно сделали с данными

В чём ошибка: очистка и преобразования выполняются, но без описания правил и причин.

Чем это опасно: другой человек не сможет понять логику изменений, а вы сами через неделю не вспомните, почему приняли именно такое решение.

Что делать вместо этого: коротко фиксировать, какие правила применялись, что удалили, что заполнили и почему.

7. Не проверяем результат после очистки

В чём ошибка: данные почистили, но не посмотрели, как изменились ключевые метрики и распределения.

Чем это опасно: можно случайно испортить данные и не заметить этого до этапа анализа или обучения.

Что делать вместо этого: после каждого важного шага пересчитывать основные метрики, смотреть распределения и сравнивать данные до и после.

8. Проверяем данные только в конце

В чём ошибка: контроль качества оставляют на последний шаг.

Чем это опасно: ошибки накапливаются по ходу всего процесса, и в конце их уже сложнее разбирать.

Что делать вместо этого: проверять данные поэтапно: после загрузки, после очистки, после преобразования и перед передачей в анализ.

Резюмируем

Хорошая аналитика начинается не с моделей и не с визуализаций. Она начинается с честного ответа на вопрос: можно ли этим данным доверять.

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

А вы проверяете данные до анализа или уже после того, как что-то пошло не так?
Интересно почитать реальные кейсы в комментариях ↓


Чтобы расти, нужно выйти из привычной зоны и сделать шаг к переменам. Можно изучить новое, начав с бесплатных материалов:

Или можно стать востребованным сотрудником и открыть открыть бóльшие перспективы в карьере с профессиональным обучением:

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


  1. Emelian
    23.04.2026 20:29

    Специально для хабровчан собрал практическое руководство по подготовке, очистке и предобработке данных для анализа и машинного обучения.

    Ура! Сейчас я вернусь к своей последней статье: «Запоминаем иностранные слова по видео-словарю, упорядоченного по грамматическим категориям и переводам» ( https://habr.com/ru/articles/1021912/ ). Там я полностью загрузил озвученный, носителем, точнее, носительницей, французско-русский онлайн-словарь, с целью извлечения текста словарных статей из полученных html-страниц и загрузки mp3-файлов, по найденным там ссылкам.

    Чтобы

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

    мне надо было проделать ту работу, о которой вы ведете, здесь, речь.

    Действительно, конечные данные там мало, что «грязные», так и не совсем понятно было в каком именно формате их извлекать.

    В итоге, нужную работу проделал, из данных получил локальный словарь в формате «Эксел» (который можно использовать как книгу для чтения) и в формате «Видео-книги».

    Однако, как вы и пишете, столкнулся с трудностями по очистке данных, для 99% которых потребовался 1% усилий, а для последнего процента процесса очистка – 99% усилий. При этом, очистка данных всё равно осталась не идеальной. «Мелких блох» ещё хватает, которые приходится вылавливать уже вручную (за пределами опубликованной статьи).

    Вот, думаю, сейчас я воспользуюсь прогрессивным и современным методом по «подготовке», «очистке» и «предобработке» данных, изложенных в вашей статье и «вуаля»! Вместо своих 99% усилий получу, условные 1-2% и буду счастлив

    Но, как говорится: «Бойтесь первого впечатления, оно может быть хорошим!». Руководство ваше (хорошо, хоть не «гайд»!), хоть и «практическое», но, реального практического примера его использования я здесь не нашел (наверное, плохо искал!). Соответственно, ничего нового для очистки моих данных не увидел. Печально! :(