Кросс-валидация

Как оценить модель надёжнее, когда одного разбиения train/test мало.

Кросс-валидация (cross-validation) — способ оценки, при котором данные несколько раз по-разному делят на обучение и проверку, а результаты усредняют.

Проблема единственного разбиения

Один train/test split даёт одну оценку — и она зависит от того, какие именно примеры попали в тест. Не повезло с разбиением — оценка получится случайно завышенной или заниженной. На небольших данных это особенно болезненно: 20% теста — это совсем немного примеров.

Идея k-fold

Кросс-валидация решает проблему так. Данные делят на k равных частей (folds, «складок»). Затем проводят k экспериментов: в каждом одна часть служит тестом, остальные k−1 — обучением. Так каждая часть ровно один раз побывает тестом. Итоговую оценку усредняют по всем k экспериментам.

При k = 5: учим на 80%, проверяем на 20% — но пять раз, каждый раз на другой пятой части. Затем берём среднее пяти оценок — оно гораздо устойчивее одиночного замера.

# 5-fold кросс-валидация: смотрим, какие части идут в тест
data = list(range(1, 11))   # 10 объектов
k = 5
fold_size = len(data) // k

for i in range(k):
    start = i * fold_size
    end = start + fold_size
    test = data[start:end]
    train = data[:start] + data[end:]
    print(f"Эксперимент {i+1}: test={test}, train={train}")

Вывод:

Эксперимент 1: test=[1, 2], train=[3, 4, 5, 6, 7, 8, 9, 10]
Эксперимент 2: test=[3, 4], train=[1, 2, 5, 6, 7, 8, 9, 10]
Эксперимент 3: test=[5, 6], train=[1, 2, 3, 4, 7, 8, 9, 10]
Эксперимент 4: test=[7, 8], train=[1, 2, 3, 4, 5, 6, 9, 10]
Эксперимент 5: test=[9, 10], train=[1, 2, 3, 4, 5, 6, 7, 8]

Видно: каждый объект ровно один раз оказался в тесте. Модель обучают и оценивают пять раз, а финальное качество — среднее пяти оценок.

Зачем это нужно

  • Надёжнее. Среднее по нескольким разбиениям меньше зависит от удачи.
  • Экономит данные. Каждый пример успевает побывать и в обучении, и в проверке — ценно, когда данных мало.
  • Удобно для подбора настроек. Сравнивая модели или значения k в kNN, по кросс-валидации выбирают устойчиво лучший вариант.

Плата за надёжность — время: модель обучается k раз вместо одного.

На практике

# Иллюстрация (scikit-learn в браузере не запустится)
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression

model = LogisticRegression()
scores = cross_val_score(model, X, y, cv=5)   # 5 складок
print("Оценки по складкам:", scores)
print("Среднее качество:", scores.mean())

Итог

  • Кросс-валидация делит данные на k частей и k раз меняет, какая часть — тест.
  • Итоговая оценка — среднее по всем k экспериментам, она устойчивее одиночной.
  • Каждый пример успевает побывать и в обучении, и в проверке — экономно на малых данных.
  • Цена — обучение модели k раз вместо одного.
Проверьте себя
1. В чём идея k-fold кросс-валидации?
AОбучить модель один раз и проверить на всех данных
BПоделить данные на k частей и k раз менять, какая часть служит тестом, затем усреднить оценки
CИспользовать только самую большую часть данных
DВообще не проверять модель
2. Чем кросс-валидация лучше одного train/test split?
AОна работает быстрее одиночного разбиения
BОценка устойчивее, меньше зависит от удачного разбиения, и данные используются экономнее
CОна не требует тестовых данных
DОна всегда даёт нулевую ошибку
3. Какова основная плата за кросс-валидацию?
AНужно больше памяти на диске
BМодель приходится обучать k раз вместо одного, то есть дольше
CТеряется часть данных навсегда
DОценка становится менее надёжной
Поддержать проект