Фундамент
~22 мин

Классический ML

Деревья, бустинг, линейные модели, кластеризация — основа большинства production-решений.

Классический ML — от линейной регрессии до градиентного бустинга

Нейросети на хайпе, но 80% production-моделей на табличных данных — это градиентный бустинг. Кредитный скоринг, прогноз оттока, рекомендации товаров, предсказание цен — везде работают «классические» алгоритмы. Они быстрее обучаются, проще в интерпретации и часто не уступают нейросетям на структурированных данных.

Классический ML делится на два больших лагеря: • Supervised learning (обучение с учителем) — есть правильные ответы (метки). Модель учится предсказывать y по x. Регрессия (предсказать число: цена квартиры) и классификация (предсказать класс: спам/не спам). • Unsupervised learning (обучение без учителя) — меток нет. Модель ищет структуру в данных: кластеризация (k-means), снижение размерности (PCA), поиск аномалий. В этой ноде фокус на supervised learning — именно его спрашивают на собеседованиях в 90% случаев.

Большая картина: как устроен ML-пайплайн

Прежде чем углубляться в конкретные алгоритмы, посмотрим на весь путь от «сырых» данных до работающей модели. Это один и тот же пайплайн для любого алгоритма — от линейной регрессии до XGBoost:

Шаг 1. Данные. Собираем таблицу: строки = объекты (пользователи, квартиры, транзакции), столбцы = признаки (features). Шаг 2. Feature engineering. Сырые данные → полезные признаки. Кодируем категории, нормализуем числа, создаём новые фичи (например, «возраст аккаунта в днях» из даты регистрации). Шаг 3. Обучение модели. Алгоритм ищет зависимость между признаками (X) и целевой переменной (y). Линейная регрессия ищет коэффициенты, дерево — пороги разбиения. Шаг 4. Предсказание. Обученная модель получает новый объект и выдаёт ответ: число (регрессия) или класс/вероятность (классификация). Шаг 5. Оценка. Сравниваем предсказания с реальностью. Метрики: MSE, MAE (регрессия), Accuracy, F1, ROC-AUC (классификация). Подробнее — в ноде Метрики классификации.

ML pipeline: данные → признаки → модель → предсказание → оценка
Общий пайплайн ML: данные → feature engineering → модель → предсказание → оценка. Этот цикл повторяется, пока качество не устроит

Линейная регрессия — первый бейзлайн

Задача: предсказать число (цену квартиры, зарплату, температуру). Линейная регрессия предполагает, что ответ — это взвешенная сумма признаков плюс свободный член. По сути — провести «лучшую прямую» через облако точек.

Аналогия: ты оцениваешь стоимость квартиры «на глазок». Каждый квадратный метр добавляет ~X рублей, каждый этаж — ещё Y, близость к метро — ещё Z. Линейная регрессия делает то же самое, но находит оптимальные X, Y, Z по данным.

ŷ — предсказание, x₁…xₙ — признаки, w₁…wₙ — веса (сколько «стоит» каждый признак), b — bias (свободный член)

Как найти оптимальные веса? Минимизируем ошибку — среднеквадратичную разницу между предсказаниями и реальными значениями:

MSE (Mean Squared Error) — средний квадрат ошибки. N — число объектов, yᵢ — правильный ответ, ŷᵢ — предсказание модели

Два способа минимизировать MSE: 1. Аналитически (нормальные уравнения): w = (X^T X)^{-1} X^T y. Точное решение за один шаг. Работает для небольших данных, но для миллионов строк — слишком медленно (O(n·d²) по памяти). 2. Градиентный спуск (gradient descent): начинаем со случайных весов, считаем градиент MSE по весам, сдвигаем веса в направлении уменьшения ошибки. Повторяем. Это универсальный метод оптимизации — он же используется в нейросетях.

Числовой пример: предсказываем цену квартиры

Простейший случай: один признак — площадь (x), целевая — цена (y, млн ₽). | Площадь (м²) | Цена (млн ₽) | |---|---| | 30 | 4.5 | | 50 | 7.0 | | 70 | 9.5 | Модель: ŷ = w·x + b. Подставим оптимальные веса (можно вычислить вручную): w = 0.125, b = 0.75. Проверяем: ŷ(30) = 0.125 × 30 + 0.75 = 4.5 ✓, ŷ(50) = 0.125 × 50 + 0.75 = 7.0 ✓. Новая квартира 60 м²: ŷ(60) = 0.125 × 60 + 0.75 = 8.25 млн ₽.

Линейная регрессия: прямая через облако точек
Линейная регрессия ищет прямую, минимизирующую сумму квадратов расстояний до точек (MSE)

Логистическая регрессия — классификация через вероятность

Теперь задача другая: предсказать не число, а класс. Купит ли пользователь подписку? Спам или не спам? Одобрить кредит или нет? Это бинарная классификация.

Идея: берём линейную комбинацию признаков (как в линейной регрессии), но пропускаем результат через сигмоиду — функцию, которая «сжимает» любое число в диапазон от 0 до 1. Получаем вероятность принадлежности к классу 1.

σ — сигмоида. Если w^T x + b = 0, то σ = 0.5 (граница). Если > 0 → ближе к 1, если < 0 → ближе к 0

Сигмоида превращает линейную комбинацию в вероятность
Сигмоида: плавный переход от 0 к 1. Точка перегиба (0.5) — decision boundary

Decision boundary (граница решения) — это гиперплоскость, где P(y=1) = 0.5, то есть w^T x + b = 0. По одну сторону — класс 0, по другую — класс 1. В 2D — это прямая, в 3D — плоскость.

Обучается логрег через log-loss (бинарная кросс-энтропия), а не MSE. Почему? MSE для классификации даёт невыпуклую функцию с локальными минимумами, а log-loss — выпуклую, с единственным глобальным минимумом.

На собесе: зачем нормализовать признаки?

Без нормализации признак «доход» (миллионы) доминирует над «возраст» (десятки). Градиентный спуск делает крошечные шаги по одним осям и огромные по другим — сходится медленно, зигзагами. StandardScaler (вычесть среднее, разделить на σ) решает проблему. Для деревьев нормализация НЕ нужна — они работают с порогами, а не с расстояниями.

Деревья решений — модель, которую можно объяснить бизнесу

Линейные модели проводят одну границу (прямую/плоскость). А что если граница сложная? Дерево решений разбивает пространство признаков на прямоугольные области, задавая последовательность вопросов: «Доход > 50K? → Возраст > 30? → Одобрить кредит».

Аналогия: врач ставит диагноз по симптомам. «Температура > 38? → Да → Кашель? → Да → Скорее всего грипп». Каждый вопрос делит пациентов на две группы. Дерево решений делает то же самое, но автоматически подбирает вопросы.

Дерево решений: одобрение кредита
Каждый узел — вопрос (условие на признак), каждый лист — решение (класс или число)

Как дерево выбирает вопрос: Gini и Entropy

На каждом шаге дерево перебирает все признаки и все пороги, выбирая тот, который лучше всего разделяет объекты по классам. «Лучше» определяется критерием:

Gini impurity: Gini = 1 − Σ pᵢ². Чистый узел (один класс): Gini = 0. Максимально «грязный» (50/50): Gini = 0.5. Дерево ищет разбиение, которое максимально снижает Gini. • Entropy (информационный выигрыш): Entropy = −Σ pᵢ · log₂(pᵢ). Чистый узел: 0. Максимально «грязный»: 1. Принцип тот же — выбираем разбиение, которое снижает «хаос». На практике разница между ними минимальна — Gini чуть быстрее (без логарифма), поэтому используется по умолчанию в sklearn.

Пример: 100 заявок на кредит (60 одобрено, 40 отказано). Gini = 1 − (0.6² + 0.4²) = 0.48. Разбиваем по «доход > 50K»: левый узел (55 одобрено, 10 отказано) → Gini = 0.26, правый (5 одобрено, 30 отказано) → Gini = 0.24. Средневзвешенный Gini = 0.65·0.26 + 0.35·0.24 = 0.253 — значительно лучше, чем 0.48.

Переобучение и pruning

Одно дерево без ограничений будет расти, пока каждый лист не станет чистым (один класс). Результат — идеальная точность на обучении и катастрофа на тесте. Дерево выучило шум, а не паттерны.

Как бороться: • Ограничение глубины (max_depth): не давать дереву расти слишком глубоко • Минимум объектов в листе (min_samples_leaf): не создавать листья из 1-2 объектов • Pruning (обрезка): вырастить полное дерево, потом «обрезать» ветви, которые не улучшают качество на валидации Но главное решение проблемы одного дерева — ансамбли.

Random Forest — сила толпы

Одно дерево нестабильно: убрал пару объектов из выборки — получил совершенно другое дерево. Высокий variance (разброс). Как это починить? Построить много деревьев и усреднить их ответы.

Аналогия: хочешь узнать температуру на улице. Один термометр может врать. Но если ты спросишь 100 человек с разными термометрами и возьмёшь среднее — результат будет точнее. Это и есть идея бэггинга (bagging = bootstrap aggregating).

Как работает Random Forest: 1. Из N объектов обучающей выборки создаём T бутстрэп-выборок — случайных выборок с возвращением (каждая размера N, но некоторые объекты повторяются, а ~37% не попадают). 2. На каждой выборке строим дерево. Ключевой трюк: на каждом разбиении дерево выбирает из случайного подмножества из m признаков (обычно m = √d для классификации, m = d/3 для регрессии). Это делает деревья некоррелированными. 3. Для предсказания собираем ответы всех деревьев: голосование (классификация) или среднее (регрессия).

Почему Random Forest лучше одного дерева? Одно дерево ошибается от шума (high variance). Среднее T некоррелированных деревьев имеет дисперсию в T раз меньше — ошибки «гасят» друг друга. При этом бэггинг не увеличивает bias — каждое дерево по-прежнему достаточно сложное. Результат: меньше variance при том же bias = лучшее качество.

Важное свойство

Random Forest не переобучается с ростом числа деревьев. Больше деревьев → точнее среднее → ниже variance. Это одно из ключевых преимуществ. На практике 100-500 деревьев обычно достаточно.

Градиентный бустинг — последовательное исправление ошибок

Random Forest строит деревья параллельно и независимо. Градиентный бустинг — принципиально другой подход: каждое новое дерево учится на ошибках предыдущих.

Аналогия: ты пишешь сочинение. Первый черновик — грубый, но покрывает основные идеи. Второй проход — исправляешь самые грубые ошибки. Третий — шлифуешь детали. Каждая итерация делает текст чуть лучше. Бустинг делает то же: каждое дерево — это «правка» предыдущего результата.

Как работает градиентный бустинг: пошагово

1. Стартовая модель: предсказываем среднее y для всех объектов. Пример: средняя цена квартир = 7 млн. 2. Вычисляем остатки (residuals): для каждого объекта разница между реальным y и текущим предсказанием. Квартира стоит 10 млн, предсказали 7 → остаток = +3. 3. Строим дерево на остатках: новое дерево учится предсказывать эти остатки (ошибки), а не исходные значения. 4. Обновляем предсказание: новое_предсказание = старое + lr × дерево(x), где lr — learning rate (обычно 0.01-0.1). 5. Повторяем шаги 2-4 сотни раз.

Числовой пример: | Квартира | Реальная цена | Шаг 0 (среднее) | Остаток | Шаг 1 (дерево 1) | Новый предсказ | |---|---|---|---|---|---| | A (30 м²) | 4.5 | 7.0 | −2.5 | −2.3 | 7 + 0.1 × (−2.3) = 6.77 | | B (50 м²) | 7.0 | 7.0 | 0 | +0.1 | 7 + 0.1 × 0.1 = 7.01 | | C (70 м²) | 9.5 | 7.0 | +2.5 | +2.2 | 7 + 0.1 × 2.2 = 7.22 | После первого дерева предсказания уже ближе к реальности. После 100-500 деревьев — ещё точнее.

XGBoost, LightGBM, CatBoost — три фреймворка

Идея градиентного бустинга одна, но реализации отличаются. Три главных фреймворка:

XGBoost (2014) — первый «промышленный» бустинг. Регуляризация в loss-функции (L1/L2 на листья). Approximate split finding для больших данных. Доминировал на Kaggle 5+ лет. LightGBM (2017, Microsoft) — leaf-wise рост дерева вместо level-wise. Вместо того чтобы расти «по уровням» (все узлы одной глубины), LightGBM растит лист с наибольшей ошибкой — быстрее сходится. Histogram-based разбиение: признаки дискретизируются в бины, поиск порога за O(#bins) вместо O(#objects). В 5-10× быстрее XGBoost на больших данных. CatBoost (2017, Яндекс) — лучшая обработка категориальных признаков: ordered target statistics вместо one-hot или label encoding. Ordered boosting — борется с target leakage при построении дерева. Работает «из коробки» без тюнинга лучше остальных.

from catboost import CatBoostClassifier

model = CatBoostClassifier(
    iterations=500,        # число деревьев
    depth=6,               # глубина каждого дерева
    learning_rate=0.05,    # шаг обучения (маленький → больше деревьев → точнее)
    cat_features=['city', 'profession'],  # категориальные признаки
    verbose=0,
)
model.fit(X_train, y_train)
print(f"Test accuracy: {model.score(X_test, y_test):.3f}")
Bias-Variance tradeoff: Random Forest снижает variance, бустинг — bias
Random Forest снижает разброс (деревья голосуют). Бустинг снижает смещение (каждое дерево исправляет ошибки). Оба борются с переобучением, но по-разному

Когда что использовать: таблица выбора алгоритма

Нет «лучшего алгоритма» — есть подходящий для задачи. Вот практические рекомендации:

| Ситуация | Алгоритм | Почему | |---|---|---| | Первый бейзлайн | Логистическая регрессия | Быстро, интерпретируемо, даёт нижнюю границу | | Мало данных (<1K) | Логрег / Random Forest | Бустинг переобучится, линейные модели — нет | | Табличные данные | CatBoost / LightGBM | Лучшее качество на табличных данных. Точка | | Есть категории | CatBoost | Ordered target stats лучше one-hot | | Большие данные (>1M строк) | LightGBM | Histogram + leaf-wise = скорость | | Нужна интерпретируемость | Логрег / одно дерево | Коэффициенты / правила читаются напрямую | | Нужна объяснимость бустинга | SHAP поверх CatBoost | Feature importance + объяснение каждого предсказания | | Изображения / текст / аудио | Нейросети | Классический ML не работает с неструктурированными данными |

Feature engineering — искусство создания признаков

Данные редко приходят в идеальном виде. Feature engineering — это подготовка и трансформация данных так, чтобы модель могла извлечь из них максимум информации. На практике качественные фичи дают больше, чем сложный алгоритм.

Нормализация (для линейных моделей и kNN): • StandardScaler: x → (x − μ) / σ. Среднее = 0, стандартное отклонение = 1. • MinMaxScaler: x → (x − min) / (max − min). Значения в [0, 1]. • Для деревьев/бустинга нормализация не нужна — они работают с порогами. Кодирование категорий:One-Hot Encoding: город → [0, 1, 0, 0]. Для линейных моделей и когда категорий мало (<20). • Label Encoding: город → 1, 2, 3. Для деревьев — ок, для линейных — опасно (модель решит, что «3 > 1»). • Target Encoding: город → средний y по этому городу. Мощно, но осторожно — risk of target leakage. CatBoost делает это правильно «из коробки». Feature importance — какие признаки реально влияют на результат: • Встроенная (в бустинге): сколько раз признак использовался в разбиениях. • Permutation importance: перемешиваем значения одного признака — смотрим, насколько упало качество. • SHAP values: объясняет вклад каждого признака в каждое конкретное предсказание. Золотой стандарт.

🎯 На собеседовании

Junior

Чем отличается регрессия от классификации? Регрессия предсказывает число (цена), классификация — класс (спам/не спам) или вероятность. • Как работает логистическая регрессия? Линейная комбинация признаков → сигмоида → вероятность класса 1. Порог 0.5 — decision boundary. • Зачем нормализовать признаки? Для линейных моделей и kNN — иначе признаки с большим масштабом доминируют. Для деревьев — не нужно. • Как работает дерево решений? Жадно выбирает лучшее разбиение по Gini/Entropy. Каждый узел — условие на признак, листья — ответы.

Middle

Bias-variance tradeoff? Bias — ошибка от упрощения модели (underfitting), variance — ошибка от подгонки под шум (overfitting). Линейная регрессия: high bias, low variance. Глубокое дерево: low bias, high variance. Бустинг снижает bias, бэггинг — variance. • Бустинг vs бэггинг? Бэггинг (RF): независимые модели на бутстрэп-выборках, усредняем → снижаем variance. Бустинг: последовательные модели, каждая учится на ошибках предыдущих → снижаем bias. • Почему бустинг лучше RF на таблицах? Последовательное исправление ошибок + регуляризация. Бустинг адаптивно фокусируется на «сложных» объектах. • XGBoost vs LightGBM vs CatBoost? XGBoost: level-wise, L1/L2 регуляризация. LightGBM: leaf-wise + histograms = быстрее. CatBoost: ordered boosting + нативные категории.

Senior

Как бустинг борется с переобучением? Learning rate (маленький шаг), ограничение глубины, subsample (случайная подвыборка на каждой итерации), L1/L2 регуляризация на листья, early stopping. • Что такое ordered boosting в CatBoost? При вычислении target statistics для категориальных признаков CatBoost использует только «прошлые» объекты (по случайной перестановке), чтобы избежать target leakage. • Когда линейная модель лучше бустинга? Мало данных (<500 объектов), линейная зависимость, нужна интерпретируемость коэффициентов, ограничения на latency (линрег = одно матричное умножение). • Как правильно делать target encoding? Только на train fold (не на val/test), с регуляризацией (сглаживание к глобальному среднему при малом числе объектов), лучше — через CatBoost ordered statistics.

Собираем всё вместе

Классический ML — это лестница от простого к сложному. Линейная регрессия — базовый бейзлайн, взвешенная сумма признаков. Логистическая регрессия — то же + сигмоида для классификации. Деревья решений — нелинейные границы, но склонны к переобучению. Random Forest — ансамбль независимых деревьев, усреднение снижает variance. Градиентный бустинг — последовательное исправление ошибок, снижает bias — и это то, что стоит в продакшне.

Если запомнить одну вещь из этой ноды: на табличных данных бустинг (CatBoost/LightGBM) — король. Но начинай с логрега как бейзлайна, а бустинг — как основная модель. Feature engineering часто важнее выбора алгоритма.

Дальше на роадмапе: Метрики классификации расскажут, как правильно оценить качество модели, а Model Selection — как бороться с переобучением через кросс-валидацию и подбор гиперпараметров.