- BrainTools - https://www.braintools.ru -
Меня зовут Руслан Каллагов, я системный аналитик в Лаборатории Globus — партнёре Нетологии по стажировкам на курсах ИТ-профессий. Уже 4,5 года я работаю в проектировании программного обеспечения и верю в инженерный подход к подготовке данных. Специально для хабровчан собрал практическое руководство по подготовке, очистке и предобработке данных для анализа и машинного обучения [1]. В нём объясняю ключевые этапы подготовки данных, показываю примеры кода, даю чек-листы и алгоритмы действий.
Я считаю, что подготовка данных — самый недооценённый этап аналитики. Его не видно в демо, за него редко благодарят, и почти никогда не закладывают время. Но именно здесь решается главный вопрос проекта: можно ли этим данным доверять вообще.
Данные почти всегда «грязные».
Подготовка = pipeline, а не набор действий.
Очистка ≠ предобработка.
Масштабирование критично для моделей.
Если процесс не автоматизирован — это долг.
По данным ежегодных опросов Anaconda (2023 [2], 2024 [3]), подготовка и очистка данных остаются наиболее времязатратными задачами дата-специалистов — вне зависимости от того, насколько автоматизирован их рабочий процесс. Исторически оценки варьировались от 45 до 80% рабочего времени (Anaconda 2020 [4], CrowdFlower 2016 [5]), и хотя инструменты за последние годы стали лучше [6], задача никуда не исчезла.
Какие термины используются в статье:
очистка данных (data cleansing) — исправление ошибок (дубликатов, пропусков, выбросов, некорректных значений);
предобработка данных (data preprocessing, wrangling) — преобразование (типы, масштабирование, кодирование, признаки);
подготовка данных (data preparation) — общий процесс (включает исследование → очистку → преобразование → проверку).
Очистка отвечает на вопрос: «Что в данных сломано».
Предобработка: «Как привести данные в рабочий вид».
Подготовка: «Как пройти путь от сырого набора до данных, которым можно доверять».
В этой статье мы используем термин «подготовка данных» как общий, и внутри него разберём очистку и предобработку как отдельные этапы.
В реальных проектах данные редко бывают аккуратными. Они содержат пропуски, дубликаты, ошибки [7] формата и противоречия — такие данные принято называть «грязными» (dirty data [8]). Это не исключение, а правило: данные поступают из разных систем, вводятся вручную, мигрируют между платформами.
Пример «грязных» данных:
| 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% [9], а значит, большинство компаний ещё не выстроили системное управление качеством данных. Даже в зрелых организациях проекты ИИ и аналитическая отчётность нередко опираются на грязные и разрозненные данные, что снижает доверие и к моделям, и к аналитике.
Чтобы не работать на ощупь, подготовку данных нужно выстраивать как пайплайн: исследование → очистка → объединение → предобработка → валидация.
На этом этапе мы ничего не исправляем — мы понимаем данные.
Смотрим структуру.
Проверяем типы.
Считаем пропуски.
Анализируем распределения.
Ищем аномалии.
Пример:
df.info()
df.isna().sum()
df.describe(include="all")
Вы можете ответить:
какие поля проблемные;
где риски;
какие шаги очистки нужны.
Теперь убираем ошибки.
Дубликаты:
df = df.drop_duplicates()
Пропуски:
df["salary"] = df["salary"].fillna(df["salary"].median())
Ошибки и выбросы:
df = df[df["age"].between(0, 120)]
Что имеем в итоге:
данные логически корректны;
нет критичных аномалий;
структура не разрушена.
Если источников несколько, их нужно согласовать.
df = users.merge(orders, on="user_id", how="left")
Потеря строк.
Дубликаты после join.
Несовпадение ключей.
Данные согласованы.
Ключи валидны.
Нет размножения строк.
Теперь приводим данные в рабочий вид.
Преобразуем типы.
Кодируем категории.
Создаём признаки.
Масштабируем числовые данные.
Масштабирование нужно, чтобы признаки были сопоставимы.
Если один признак — в тысячах, а другой — в единицах, модель будет считать первый важнее.
StandardScaler: центрирует данные, стандартное отклонение = 1.
MinMaxScaler: приводит к диапазону [0, 1].
RobustScaler: устойчив к выбросам.
Пример:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df[["age", "salary"]] = scaler.fit_transform(df[["age", "salary"]])
Признаки сопоставимы.
Модель обучается стабильнее.
Нет перекоса из-за масштаба.
Финальный контроль. Пример:
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()
На этом этапе данные приводят в вид, с которым можно работать дальше:
строки → числа;
даты → datetime;
единицы измерения → к одному стандарту.
Если типы данных некорректны, дальше почти гарантированы баги от неправильных расчётов до падения пайплайнов.
Для моделей данные почти всегда нужно преобразовать:
категориальные признаки → закодировать;
числовые → масштабировать.
Пример:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df[['age', 'salary']] = scaler.fit_transform(df[['age', 'salary']])
Это критично для алгоритмов, чувствительных к масштабу признаков.
После всех преобразований нужно задать себе простой вопрос: «Стали ли данные лучше, чем были?»
Минимум, что стоит проверить:
не потеряли ли вы важные сегменты;
не изменились ли распределения радикально;
не появились ли новые аномалии.
Если вы не смотрите на данные после очистки, вы работаете вслепую.
На этом этапе обычно возникает вопрос: «Окей, понятно, что делать. А какие инструменты для этого использовать?».
Ниже — практический минимум, который закрывает большинство задач.
Если данные табличные (CSV, Excel, выгрузки из БД), то в большинстве проектов работа начинается именно здесь [10].
Когда использовать:
первичная загрузка данных;
поиск дубликатов и пропусков;
базовая очистка и трансформации;
быстрый анализ структуры.
Как применять на практике:
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 [11] позволяет описывать ожидания от данных в виде схем: типы, диапазоны, обязательные поля. Это особенно полезно, когда данные приходят регулярно.
Когда использовать:
данные обновляются ежедневно или по расписанию;
важно ловить ошибки до анализа;
нужно формализовать требования к данным.
Как применять на практике:
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)
Если данные не соответствуют ожиданиям, вы получите явное сообщение об ошибке — а не анализ, который незаметно даёт неверный результат.
Инструмент [12] для описания ожиданий к данным и автоматической проверки качества.
Когда использовать:
ETL/ELT-пайплайны;
аналитика в продакшене;
нужно логировать проблемы с данными.
Типичные проверки:
столбец не должен быть пустым;
значения в диапазоне;
уникальность ключей;
допустимые категории.
Идея использования: данные пришли → прогнали проверки → только после этого пошли в аналитику или модель.
Для машинного обучения подготовка данных почти всегда включает кодирование и масштабирование [13].
Когда использовать:
обучение моделей;
чувствительные к масштабу алгоритмы;
пайплайны 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.
Когда использовать:
большие объёмы данных;
агрегации;
фильтрация мусора на входе.
Как применять на практике:
SELECT DISTINCT
user_id,
created_at,
salary
FROM users
WHERE salary IS NOT NULL
AND salary >= 0;
Чем раньше вы отсекаете мусор, тем дешевле и надёжнее аналитика.
Jupyter [14] и Google Colab [15] — инструменты не для продакшена, но хорошо подходят для исследования данных.
Когда использовать:
исследовательская аналитика;
проверка гипотез;
визуальный контроль очистки.
Практика «очистил → сразу посмотрел график» экономит часы отладки.
Нужно быстро посмотреть данные → pandas + Jupyter.
Нужно формализовать правила → Pandera.
Нужно следить за качеством в продакшене → Great Expectations.
Готовите данные для модели → scikit-learn.
Большие объёмы → SQL как можно раньше.
На практике подготовка данных почти всегда проходит в два этапа:
ручная предобработка (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")
df.info()
df.isna().sum()
df.duplicated().sum()
Что выясняем:
есть пропуски в salary;
есть дубликаты;
есть некорректные значения возраста.
# Удаляем дубликаты
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")Шаг 4. Масштабирование
scaler = StandardScaler()
df[["age", "salary"]] = scaler.fit_transform(df[["age", "salary"]])
assert df["user_id"].notna().all()
На этом этапе у вас уже есть рабочая логика [16] подготовки данных. Но пока она существует только в виде набора ручных действий.
Ручной режим перестаёт работать, как только наступает одно из условий:
данные обновляются регулярно;
появляется модель или отчёт;
процесс нужно повторять [17].
Теперь задача — сделать процесс воспроизводимым.
Те же шаги оформляются в функцию:
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
Автоматизация — уже не опция, а необходимость, если выполняется хотя бы одно из условий:
данные обновляются регулярно;
вы повторяете одни и те же шаги;
результат влияет на бизнес-решения;
есть модель или отчёт в проде.
Ручная предобработка отвечает на вопрос: «Что нужно сделать с данными?»
Автоматизированная — на вопрос: «Как делать это стабильно каждый раз?»
Если у вас есть только первый этап — у вас прототип. Если есть оба — у вас система.
Собрал ошибки, которые встречаются чаще всего, — и советы, что делать вместо них. Этот блок удобно читать как короткий чек-лист перед релизом или передачей данных в модель.
В чём ошибка: строки с пропусками или аномалиями удаляют автоматически просто потому, что так проще.
Чем это опасно: можно случайно выкинуть важный сегмент данных и исказить картину.
Что делать вместо этого: сначала понять, почему появились пропуски, и только потом выбирать стратегию: удаление, заполнение или отдельная обработка.
В чём ошибка: импутация делается механически — средним, медианой или константой — без проверки, подходит ли это для конкретного признака.
Чем это опасно: можно сместить распределение и ухудшить качество анализа или модели.
Что делать вместо этого: сначала посмотреть распределение признака и понять, насколько выбранный способ заполнения искажает данные.
В чём ошибка: данные проверяются только на формальные ошибки, но не на здравый смысл и бизнес-логику.
Чем это опасно: в наборе могут остаться записи вроде отрицательного возраста, невозможной даты или несогласованных статусов.
Что делать вместо этого: добавлять бизнес-валидацию — проверять не только типы и диапазоны, но и смысловые ограничения.
В чём ошибка: очистка делается вручную, по месту, без скриптов и без фиксированной логики.
Чем это опасно: процесс нельзя воспроизвести, а значит, нельзя нормально обновить данные или отладить результат.
Что делать вместо этого: оформлять подготовку данных в виде кода или пайплайна, чтобы любой шаг можно было повторить.
В чём ошибка: работа идёт только с одной копией датасета.
Чем это опасно: если что-то пошло не так, откатиться уже некуда.
Что делать вместо этого: всегда хранить raw-версию отдельно и вести версии после каждого этапа подготовки.
В чём ошибка: очистка и преобразования выполняются, но без описания правил и причин.
Чем это опасно: другой человек не сможет понять логику изменений, а вы сами через неделю не вспомните, почему приняли именно такое решение.
Что делать вместо этого: коротко фиксировать, какие правила применялись, что удалили, что заполнили и почему.
В чём ошибка: данные почистили, но не посмотрели, как изменились ключевые метрики и распределения.
Чем это опасно: можно случайно испортить данные и не заметить этого до этапа анализа или обучения.
Что делать вместо этого: после каждого важного шага пересчитывать основные метрики, смотреть распределения и сравнивать данные до и после.
В чём ошибка: контроль качества оставляют на последний шаг.
Чем это опасно: ошибки накапливаются по ходу всего процесса, и в конце их уже сложнее разбирать.
Что делать вместо этого: проверять данные поэтапно: после загрузки, после очистки, после преобразования и перед передачей в анализ.
Хорошая аналитика начинается не с моделей и не с визуализаций. Она начинается с честного ответа на вопрос: можно ли этим данным доверять.
Исправить тип столбца, удалить дубликаты, заполнить пропуски по правилу, а не по умолчанию — каждое из этих действий стоит минут, но экономит часы отладки и недели переделок. Подготовка данных — это не служебная часть проекта. Это фундамент, на котором держится всё остальное.
А вы проверяете данные до анализа или уже после того, как что-то пошло не так?
Интересно почитать реальные кейсы в комментариях ↓
Чтобы расти, нужно выйти из привычной зоны и сделать шаг к переменам. Можно изучить новое, начав с бесплатных материалов:
практического гайда «ИИ вместо переработок: как освободить 20+ часов в неделю [18]»;
совместного с Zigmund.Online курса «Карьера без страха [19]»;
воркшопа «1C-аналитик: погружение в профессию на практике [20]»;
практического курса «Обучение основам работы в Figma с нуля [21]»;
вводного курса магистратуры НИУ ВШЭ «Инженерия данных [22]».
Или можно стать востребованным сотрудником и открыть открыть бóльшие перспективы в карьере с профессиональным обучением:
на программе повышения квалификации «Python для анализа данных [23]»;
на курсе «Продвинутый SQL [24]»;
на программе профессиональной переподготовки «Аналитика данных [25]», которая разработана совместно с МФТИ;
на курсе «Специалист по искусственному интеллекту [26]»;
в магистратуре НИУ ВШЭ «Инженерия данных [27]».
Автор: Mr_Manro
Источник [28]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/29279
URLs in this post:
[1] обучения: http://www.braintools.ru/article/5125
[2] 2023: https://www.anaconda.com/lp/state-of-data-science-report-2023
[3] 2024: https://www.anaconda.com/resources/report/state-of-data-science-report-2024
[4] Anaconda 2020: https://www.anaconda.com/resources/whitepaper/state-of-data-science-2020
[5] CrowdFlower 2016: https://www2.cs.uh.edu/~ceick/UDM/CFDS16.pdf
[6] стали лучше: https://habr.com/ru/companies/netologyru/articles/1003524/
[7] ошибки: http://www.braintools.ru/article/4192
[8] dirty data: https://www.ibm.com/think/topics/dirty-data
[9] составлял лишь 45%: https://ria.ru/20260122/rossija-2069460786.html
[10] здесь: https://pandas.pydata.org
[11] Pandera: https://pandera.readthedocs.io/en/stable/
[12] Инструмент: https://greatexpectations.io
[13] кодирование и масштабирование: https://scikit-learn.org/stable/
[14] Jupyter: https://jupyter.org/
[15] Google Colab: https://colab.research.google.com/
[16] логика: http://www.braintools.ru/article/7640
[17] повторять: http://www.braintools.ru/article/4012
[18] ИИ вместо переработок: как освободить 20+ часов в неделю: https://netology.ru/programs/guide-ai?utm_source=habr&utm_medium=externalblog&utm_campaign=b2b_guide-ai_guide_habr_brand_article-23042026_media
[19] Карьера без страха: https://netology.ru/programs/kariera-bez-straha?utm_source=habr&utm_medium=externalblog&utm_campaign=activ_career_change_bou_habr_brand_article-23042026_media
[20] 1C-аналитик: погружение в профессию на практике: https://netology.ru/programs/1c-analitika-freee?utm_source=habr&utm_medium=externalblog&utm_campaign=re_it_1cfree_bou_habr_brand_article-23042026_media
[21] Обучение основам работы в Figma с нуля: https://netology.ru/programs/osnovy-figma?utm_source=habr&utm_medium=externalblog&utm_campaign=re_ki_figma_bou_habr_brand_article-23042026_media
[22] Инженерия данных: https://netology.ru/programs/dataengineering-pk?utm_source=habr&utm_medium=externalblog&utm_campaign=bhe_bhemde-pk_bou_habr_brand_article-23042026_media
[23] Python для анализа данных: https://netology.ru/programs/python-for-analytics?utm_source=habr&utm_medium=externalblog&utm_campaign=up_it_pydp_ou_habr_brand_article-23042026_media
[24] Продвинутый SQL: https://netology.ru/programs/sql-for-data-analysis?utm_source=habr&utm_medium=externalblog&utm_campaign=up_it_sqlp_ou_habr_brand_article-23042026_media
[25] Аналитика данных: https://netology.ru/programs/professiya-analitik-dannyh-mfti?utm_source=habr&utm_medium=externalblog&utm_campaign=bhe_bhelds_ou_habr_brand_article-23042026_media
[26] Специалист по искусственному интеллекту: https://netology.ru/programs/specialist-po-iskusstvennomu-intellektu?utm_source=habr&utm_medium=externalblog&utm_campaign=re_it_aie_ou_habr_brand_article-23042026_media
[27] Инженерия данных: https://netology.ru/programs/dataengineering?utm_source=habr&utm_medium=externalblog&utm_campaign=bhe_bhemde_ou_habr_brand_article-23042026_media
[28] Источник: https://habr.com/ru/companies/netologyru/articles/1026754/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1026754
Нажмите здесь для печати.