Автор: Илья Воронцов, аналитик данных и ML-специалист
Привет! Я Илья Воронцов. За годы в Data Science я видел, как команды тратят недели на модели, которые в итоге не работают. Почему? Базовые ошибки при обучении моделей машинного обучения — это не про сложную математику, а про простые промахи: от данных до валидации. В этой статье разберём 10 ключевых ловушек, которые встречаются у новичков и даже опытных специалистов. Для каждой — причина, последствия и чёткий план действий. Всё с примерами из реальных проектов, чтобы вы могли сразу применить.
Если вы строите первую модель или отлаживаете пайплайн в бизнес-задаче (предсказание оттока клиентов, сегментация или рекомендационная система), эти советы сэкономят часы. Давайте разберём по шагам.
Почему ошибки в обучении моделей — это проблема №1 для ML-проектов
В 80% случаев модели проваливаются не из-за слабого алгоритма, а из-за ошибок на этапе подготовки и обучения. По моему опыту в проектах для e-commerce и финансов, игнорирование базовых вещей приводит к переобучению, низкой точности и моделям, которые не работают на проде.
Ключевые последствия:
- Трата времени: неделя на «идеальную» модель, которая даёт 50% accuracy.
- Бизнес-риски: неверные предсказания оттока приводят к потере клиентов.
- Разочарование в ML: «Мы попробовали, не сработало».
Решение — системный подход. Ниже таблица с топ-ошибками и быстрыми фиксами для сканирования.
| Ошибка | Частота (по моему опыту) | Быстрый фикс |
|---|---|---|
| Недостаток данных | 40% | Аугментация + синтетика |
| Неправильный split | 25% | Stratified K-Fold |
| Игнор feature engineering | 15% | Корреляция + SHAP |
| Переобучение | 10% | Early stopping + dropout |
Теперь по порядку.
Ошибка 1: Недостаточно данных для обучения модели
Почему происходит: Новички берут 100–500 строк и ждут чуда. Модели типа Random Forest или нейросетей требуют тысяч примеров, чтобы уловить паттерны. На практике даже для простой логистической регрессии на десяти фичах 500 объектов — это почти гарантированная нестабильность коэффициентов.
Последствия: Модель «запоминает» данные, но на новых — полный провал (accuracy падает на 20–30%). В задаче предсказания цен на жильё с 300 объектами модель дала RMSE 50k рублей на train, но 200k на test. Разрыв в четыре раза — типичный признак, что данных катастрофически мало.
Как исправить:
- Проверьте объём: для табличных данных — минимум 1k строк на класс, но если зависимость сложная, может потребоваться в разы больше. Ориентируйтесь не на абсолютное число, а на стабильность метрик при кросс-валидации.
- Аугментируйте: для изображений — повороты, зеркала (библиотека Albumentations). Для текстов можно использовать обратный перевод или замену синонимов.
- Генерируйте синтетику: SMOTE для несбалансированных классов, но помните — он создаёт линейные комбинации, что может внести шум, если данные не очень разделимы. Для сложных случаев лучше GAN или вариационные автоэнкодеры.
- Практика: В Python:
from imblearn.over_sampling import SMOTE; smote = SMOTE(); X_res, y_res = smote.fit_resample(X, y).
Проверка: Train/test gap < 5%. Инструмент: scikit-learn train_test_split(test_size=0.2). Если gap больше, модель не обобщает — либо данных мало, либо переобучение.
Ошибка 2: Неправильный разбиение данных (data leakage и bias)
Почему: Берут случайный split, не учитывая временные ряды или стратификацию. Leakage — когда future данные просачиваются в train. Например, при прогнозировании продаж случайное перемешивание позволяет модели «увидеть» будущие цены через идентификаторы или косвенные признаки.
Последствия: Модель показывает 95% accuracy на валидации, но 60% на проде. В реальном проекте по оттоку клиентов мы случайно включили в train данные о пост-оттоковых действиях (жалобы после ухода) — модель идеально предсказывала отток, но на новых клиентах была бесполезна.
Как исправить:
- Временные данные:
train = df[df['date'] < '2025-01-01']. Всегда делайте split по времени, а не случайно. Если данных мало, используйте скользящий кросс-валидационный сплит (TimeSeriesSplit). - Несбалансированные классы: StratifiedKFold (n_splits=5). Он сохраняет пропорции классов в каждом фолде, что критично для редких событий.
- Leakage чек: Удалите target из features, проверьте корреляцию признаков с target. Если какой-то признак имеет подозрительно высокую корреляцию (например, 0.9), возможно, он содержит информацию о будущем.
Код-пример:
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
for train_idx, val_idx in skf.split(X, y):
X_train, X_val = X[train_idx], X[val_idx]
y_train, y_val = y[train_idx], y[val_idx]
Ошибка 3: Игнорирование feature engineering
Почему: «Сырые» данные кидают в модель без обработки. Фичи коррелированы, пропуски не заполнены. Часто новички считают, что градиентный бустинг «сам разберётся», но даже XGBoost может запутаться в мультиколлинеарности, если признаки дублируют информацию.
Последствия: Модель путает сигналы, accuracy на 10–15% ниже. В задаче оттока клиентов возраст и стаж коррелированы — модель «сходит с ума», приписывая важность то одному, то другому, и интерпретация становится ненадёжной.
Шаги по фиксу:
- Заполнение пропусков: Median для числовых, mode для категориальных (
df.fillna(df.median())). Но лучше анализировать природу пропуска: если он не случаен, создайте отдельный бинарный признак «был ли пропуск». - Кодирование: OneHot для номинальных, Target Encoding для высококардинальных — но осторожно, с регуляризацией (smoothing), чтобы избежать переобучения на редких категориях.
- Новые фичи: Взаимодействия (age * income), биннинг, полиномы. В одном проекте добавление признака «средний чек за последние 30 дней» подняло ROC-AUC на 0.05.
- Отбор: SHAP values или SelectKBest. SHAP хорош для интерпретации, но требует обученной модели; SelectKBest быстрее для отсеивания шума на старте.
Таблица топ-инструментов:
| Задача | Инструмент | Пример |
|---|---|---|
| Корреляция | df.corr() | Удалить >0.9 |
| Важность фич | SHAP | shap.summary_plot() |
| Масштабирование | StandardScaler | Перед градиентным бустингом |
Ошибка 4: Переобучение (overfitting) — модель зубрит train
Почему: Слишком сложная модель (глубокий RF, большая NN) на малых данных. Деревья без ограничения глубины могут идеально запомнить обучающую выборку, включая шум.
Симптомы: Train accuracy 98%, val 75%. Разрыв >5% уже повод насторожиться. В одном проекте по кредитному скорингу мы получили AUC 0.99 на train и 0.72 на test — модель выучила идентификаторы клиентов, а не закономерности.
Фиксы:
- Регуляризация: L1/L2 в логистике, dropout (0.2–0.5) в NN. L1 также помогает отбирать признаки, зануляя коэффициенты.
- Early stopping: В Keras:
callbacks=[EarlyStopping(patience=10)]. Терпение в 10 эпох — стандарт, но если loss на валидации скачет, лучше уменьшить до 5. - Ансамбли: Bagging (RF) вместо одной модели. Случайный лес сам по себе менее склонен к переобучению, чем одно глубокое дерево.
- Кросс-валидация: Всегда 5-fold. Она не лечит переобучение, но позволяет его вовремя заметить.
Практика: Мониторьте с TensorBoard или MLflow. В MLflow удобно логировать кривые обучения и сравнивать эксперименты.
Ошибка 5: Подбор гиперпараметров наугад
Почему: «По умолчанию» из sklearn — редко оптимально. Например, n_estimators=100 в Random Forest может быть избыточно для простой задачи и недостаточно для сложной.
Как делать правильно:
- GridSearchCV для малого поиска — когда пространство параметров невелико, и вы можете позволить полный перебор.
- Optuna или Hyperopt для байесовского поиска. Optuna удобнее благодаря встроенной визуализации и возможности прерывать и возобновлять поиск.
- Пример для XGBoost:
optuna.create_study(direction='maximize'). Определите разумные диапазоны: learning_rate от 0.01 до 0.3, max_depth от 3 до 10.
Время экономия: 2–3 часа vs неделя ручного тюнинга. Но помните: даже байесовский поиск не спасёт, если не настроена функция потерь или неправильно выбрана метрика.
Ошибка 6: Неправильный выбор метрики
Почему: Accuracy для несбалансированных данных — обман. Если положительный класс составляет 1%, модель, предсказывающая всегда отрицательный, получит accuracy 99%, но не найдёт ни одного нужного случая.
Выбор по задаче:
| Задача | Метрика | Почему |
|---|---|---|
| Бинарная классификация | F1-score, ROC-AUC | Учёт классов |
| Регрессия | RMSE, MAE | Разный вес ошибок |
| Несбалансированные | Precision@K | Бизнес-цена |
На практике лучше согласовать метрику с бизнес-заказчиком. Например, в задаче оттока важнее recall (не пропустить уходящих), а в задаче фрод-мониторинга — precision (чтобы не блокировать честные транзакции).
Код: from sklearn.metrics import classification_report — он даёт полную картину по каждому классу.
Ошибка 7: Игнор outliers и аномалий
Почему: Не чистят данные — модель учится на шуме. Одиночный выброс в регрессии может сильно сместить линию, особенно если используется MSE.
Фикс:
- Визуализация: boxplot. Быстро показывает экстремальные значения.
- Z-score >3 — удалить или winsorize. Winsorizing (замена на пороговые значения) предпочтительнее, когда данных мало и жалко терять наблюдения.
- Isolation Forest для авто-детекта. Хорош для многомерных выбросов, которые не видны в одномерных распределениях.
Пример: В ценах на товары outliers от «1 рубль» искажают регрессию. В одном проекте после удаления таких записей RMSE снизился на 30%.
Ошибка 8: Забытые категориальные переменные
Почему: OrdinalEncoder вместо OneHot — модель видит порядок, которого нет. Для номинальных категорий (страна, цвет) порядковое кодирование вносит ложную иерархию.
Правильно: pd.get_dummies() или CategoryEncoders. Если категорий много, используйте Target Encoding с регуляризацией или Count Encoding. А ещё лучше — CatBoost, который умеет обрабатывать категории на лету, но всё равно стоит проверять, не появилось ли смещения.
Ошибка 9: Нет валидации на hold-out
Почему: Только train/test — не видно стабильности. Одна случайная разбивка может дать оптимистичную оценку, особенно на малых данных.
Фикс: 70/15/15 split + K-Fold. Отложенный hold-out (15%) не участвует ни в обучении, ни в подборе гиперпараметров — это финальный экзамен. Если модель хорошо работает на кросс-валидации, но проваливается на hold-out, значит, вы переоптимизировали под валидационные фолды.
Ошибка 10: Модель не деплоится (игнор MLOps)
Почему: Jupyter-ноутбук не превращается в API. Модель, которая работает в ноутбуке, часто не воспроизводится из-за несохранённых зависимостей, путей к данным и версий библиотек.
Шаги: Docker + FastAPI + MLflow для трекинга. Заверните модель в контейнер с фиксированными версиями пакетов, сделайте простой REST API. MLflow сохранит параметры, метрики и артефакты, чтобы можно было откатиться к удачной версии.
Чек-лист: как обучать модель без ошибок
- Собрал >1k данных?
- Stratified split?
- Features: scale, encode, engineer?
- CV score > threshold?
- No overfitting (gap <5%)?
- Метрика под бизнес?
- Тест на hold-out?
Скопируйте в Notion — используйте перед каждым обучением.
FAQ: Ответы на частые вопросы об ошибках в обучении моделей
Что делать, если данных мало для машинного обучения?
Начните с аугментации (SMOTE) или transfer learning (HuggingFace). Если <500 строк — рассмотрите rule-based подход. В некоторых случаях помогает генерация синтетических данных с помощью GAN, но это требует аккуратной проверки на реалистичность. Иногда лучше собрать больше данных, чем пытаться выжать невозможное из крошечной выборки.
Как быстро проверить переобучение?
Plot learning curves: train vs val loss. Если расходятся — добавьте регуляризацию. Ещё один быстрый тест: сравните качество на train и test; если разница больше 5–10%, модель переобучена. Для нейросетей полезно смотреть на динамику весов: резкие скачки могут указывать на нестабильность.
Лучший фреймворк для новичков?
Scikit-learn для старта, XGBoost для бустинга, PyTorch для кастомных NN. Scikit-learn даёт единообразный API и отличную документацию. XGBoost часто выигрывает «из коробки» на табличных данных. PyTorch более гибкий, но требует понимания автоматического дифференцирования.
Сколько времени на feature engineering?
30–50% всего времени проекта. Это даёт +15–20% к accuracy. В реальных проектах генерация осмысленных признаков часто важнее выбора модели. Не жалейте времени на анализ предметной области и создание признаков, отражающих бизнес-логику.
Как измерить качество модели в продакшене?
A/B-тест с baseline + мониторинг drift (Alibi Detect). Сравните новую модель с текущим решением на реальном трафике. Отслеживайте дрейф данных и концепций: если распределение признаков изменилось, модель может деградировать незаметно для стандартных метрик.
Эта статья — ваш щит от типичных фейлов. Примените на следующем проекте и увидите разницу. Если есть кейсы — пишите в комментариях, разберём вместе!