Кросс-валидация и подбор гиперпараметров
Один сплит train/test даёт шумную оценку, а подбор гиперпараметров по тесту тихо завышает качество. Кросс-валидация, вложенная валидация, grid против random search и байесовская оптимизация — как честно выбрать модель и не обмануть себя.
Интуиция: почему одного сплита мало
Ты отложил 20% данных в тест, обучился на остальных, померил метрику — 0.83. Пересыпал данные с другим случайным зерном (random seed) — стало 0.79. Ещё раз — 0.86. Проблема в том, что при малой выборке сам результат зависит от того, какие именно точки попали в тест: оценка качества сама по себе шумит. Одно число без разброса вокруг него — это иллюзия точности.
Кросс-валидация (cross-validation) убирает случайность выбора, прогоняя проверку много раз по разным разбиениям и усредняя. Мы получаем не одно число, а среднее ± разброс — и второе не менее важно, чем первое.
k-fold кросс-валидация
Делим данные на k равных частей (folds). Затем k раз повторяем: обучаемся на k−1 частях, проверяемся на оставшейся. Каждая точка ровно один раз побывает в роли валидации. Итог — среднее метрик и их стандартное отклонение (standard deviation):
Типичный выбор — k = 5 или k = 10: компромисс между устойчивостью оценки и стоимостью (обучать приходится k раз). Крайний случай — leave-one-out (LOO), где k равно числу объектов: почти несмещённо, но дорого и с большим разбросом. Для несбалансированных классов берут стратификацию (stratified k-fold) — доля классов в каждом фолде сохраняется, иначе редкий класс может целиком провалиться в один фолд.
Прогони CV в честном режиме: перебор степеней выберет что-то умеренное (d ≈ 3–5), а RMSE на отложенном «проде» окажется близко к CV-оценке — оценке можно верить. Теперь переключи на «подбираю по тесту» и снова прогони: алгоритм подстроит степень прямо под «прод», оценка станет красиво низкой — но это та же выборка, по которой отчитываемся. Разрыв между приукрашенной оценкой и честным качеством подсвечен красным: так утечка обманывает.
Главная ловушка: подбор гиперпараметров по тесту
Как только вы выбираете степень полинома, глубину дерева или λ «потому что на тесте вышло лучше», тест перестаёт быть честной оценкой — вы к нему подстроились. Это утечка (data leakage): по многократному подглядыванию в тест просачивается оптимизм. Правило: тест трогают ровно один раз, в самом конце. Для подбора нужен отдельный валидационный набор (validation set) или кросс-валидация внутри обучающей части.
Но и это не всё: если вы кросс-валидацией и подбираете гиперпараметры, и той же CV-оценкой отчитываетесь о качестве — оценка снова завышена, ведь выбор лучшего из многих вариантов сам по себе оптимистичен. Честный способ — вложенная кросс-валидация (nested CV): внешний цикл даёт непредвзятую оценку, а внутренний цикл на каждой его итерации подбирает гиперпараметры отдельно. Дорого (перемножаются два цикла), но это единственный корректный ответ на вопрос «сколько будет стоить весь пайплайн подбора».
Как перебирать гиперпараметры
- Grid search (полный перебор по сетке). Задаём для каждого гиперпараметра список значений и проверяем все комбинации. Прост и воспроизводим, но число комбинаций растёт экспоненциально с размерностью — «проклятие размерности» для перебора.
- Random search (случайный поиск). Берём случайные точки из заданных диапазонов. Бергстра и Бенжио показали: когда качество реально зависит лишь от одного-двух гиперпараметров из многих, случайный поиск при том же бюджете пробует больше разных значений важного параметра — и находит лучший режим быстрее, чем сетка, тратящая пробы на неважные оси.
- Байесовская оптимизация (Bayesian optimization). Строим суррогатную модель «гиперпараметры → качество» и на каждом шаге выбираем следующую точку так, чтобы максимизировать ожидаемое улучшение — баланс исследования и использования. Так работают Optuna (алгоритм TPE) и Hyperopt: меньше проб на тот же результат, ценой сложности и последовательности запусков.
- Ранняя остановка как подбор. Число эпох (epochs) — тоже гиперпараметр: early stopping по валидационной кривой подбирает его автоматически, останавливаясь в минимуме валидации.
- «Зачем нужна валидация, если есть тест?» — тест трогают один раз для честной итоговой оценки; подбор по тесту = утечка и завышенное качество. Гиперпараметры выбирают по валидации/CV.
- «Что такое nested CV и когда он нужен?» — внешний цикл честно оценивает пайплайн, внутренний подбирает гиперпараметры; нужен, чтобы оценка не была завышена самим фактом выбора лучшего варианта.
- «Grid search или random search?» — при малой размерности и дискретных значениях — grid; в многомерном пространстве, где важны лишь пара параметров, эффективнее random (Бергстра) или байесовская оптимизация.
- «Как кросс-валидировать временной ряд?» — только forward-chaining/walk-forward; случайные фолды дают утечку из будущего.