Привет, Хабр! Меня зовут Руслан Каллагов, я системный аналитик в Лаборатории 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. Исследование и профилирование данных
На этом этапе мы ничего не исправляем — мы понимаем данные.
Что делаем
Смотрим структуру.
Проверяем типы.
Считаем пропуски.
Анализируем распределения.
Ищем аномалии.
Пример:
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. автоматизированная предобработка: как это выглядит в реальной работе
На практике подготовка данных почти всегда проходит в два этапа:
ручная предобработка (exploration mode);
автоматизированная предобработка (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. Проверяем данные только в конце
В чём ошибка: контроль качества оставляют на последний шаг.
Чем это опасно: ошибки накапливаются по ходу всего процесса, и в конце их уже сложнее разбирать.
Что делать вместо этого: проверять данные поэтапно: после загрузки, после очистки, после преобразования и перед передачей в анализ.
Резюмируем
Хорошая аналитика начинается не с моделей и не с визуализаций. Она начинается с честного ответа на вопрос: можно ли этим данным доверять.
Исправить тип столбца, удалить дубликаты, заполнить пропуски по правилу, а не по умолчанию — каждое из этих действий стоит минут, но экономит часы отладки и недели переделок. Подготовка данных — это не служебная часть проекта. Это фундамент, на котором держится всё остальное.
А вы проверяете данные до анализа или уже после того, как что-то пошло не так?
Интересно почитать реальные кейсы в комментариях ↓
Чтобы расти, нужно выйти из привычной зоны и сделать шаг к переменам. Можно изучить новое, начав с бесплатных материалов:
практического гайда «ИИ вместо переработок: как освободить 20+ часов в неделю»;
совместного с Zigmund.Online курса «Карьера без страха»;
воркшопа «1C-аналитик: погружение в профессию на практике»;
практического курса «Обучение основам работы в Figma с нуля»;
вводного курса магистратуры НИУ ВШЭ «Инженерия данных».
Или можно стать востребованным сотрудником и открыть открыть бóльшие перспективы в карьере с профессиональным обучением:
на программе повышения квалификации «Python для анализа данных»;
на курсе «Продвинутый SQL»;
на программе профессиональной переподготовки «Аналитика данных», которая разработана совместно с МФТИ;
на курсе «Специалист по искусственному интеллекту»;
в магистратуре НИУ ВШЭ «Инженерия данных».
Emelian
Ура! Сейчас я вернусь к своей последней статье: «Запоминаем иностранные слова по видео-словарю, упорядоченного по грамматическим категориям и переводам» ( https://habr.com/ru/articles/1021912/ ). Там я полностью загрузил озвученный, носителем, точнее, носительницей, французско-русский онлайн-словарь, с целью извлечения текста словарных статей из полученных html-страниц и загрузки mp3-файлов, по найденным там ссылкам.
Чтобы
мне надо было проделать ту работу, о которой вы ведете, здесь, речь.
Действительно, конечные данные там мало, что «грязные», так и не совсем понятно было в каком именно формате их извлекать.
В итоге, нужную работу проделал, из данных получил локальный словарь в формате «Эксел» (который можно использовать как книгу для чтения) и в формате «Видео-книги».
Однако, как вы и пишете, столкнулся с трудностями по очистке данных, для 99% которых потребовался 1% усилий, а для последнего процента процесса очистка – 99% усилий. При этом, очистка данных всё равно осталась не идеальной. «Мелких блох» ещё хватает, которые приходится вылавливать уже вручную (за пределами опубликованной статьи).
Вот, думаю, сейчас я воспользуюсь прогрессивным и современным методом по «подготовке», «очистке» и «предобработке» данных, изложенных в вашей статье и «вуаля»! Вместо своих 99% усилий получу, условные 1-2% и буду счастлив
Но, как говорится: «Бойтесь первого впечатления, оно может быть хорошим!». Руководство ваше (хорошо, хоть не «гайд»!), хоть и «практическое», но, реального практического примера его использования я здесь не нашел (наверное, плохо искал!). Соответственно, ничего нового для очистки моих данных не увидел. Печально! :(