Какие стратегии кросс-валидации вы знаете и когда их применяете?

«Какие стратегии кросс-валидации вы знаете и когда их применяете?» — вопрос из категории Классическое ML, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В зависимости от структуры данных и задачи я выбираю разные стратегии кросс-валидации (CV), чтобы получить надежную оценку обобщающей способности модели.

Основные стратегии и их применение:

  1. K-Fold Cross-Validation Стандартный выбор для большинства задач с независимыми и одинаково распределенными (IID) данными. Данные случайно перемешиваются и разбиваются на K равных частей (фолдов).

    from sklearn.model_selection import KFold
    import numpy as np
    X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])
    y = np.array([1, 2, 3, 4, 5])
    kf = KFold(n_splits=5, shuffle=True, random_state=42)
    for train_index, val_index in kf.split(X):
        X_train, X_val = X[train_index], X[val_index]
        y_train, y_val = y[train_index], y[val_index]
        # Обучение и оценка модели
  2. Stratified K-Fold Когда применяю: Для задач классификации с несбалансированными классами. Эта стратегия сохраняет процентное соотношение классов в каждом фолде, что дает более стабильную оценку метрик (например, F1-score для миноритарного класса).

    from sklearn.model_selection import StratifiedKFold
    skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
    # Используется аналогично KFold, но передается и y для стратификации
    for train_index, val_index in skf.split(X, y):
        ...
  3. Time Series Split (или TimeSeriesCV) Когда применяю: Для данных, имеющих временную зависимость (финансовые котировки, сенсорные данные). Важно не допустить "утечки будущего в прошлое". Каждый последующий тренировочный набор является надмножеством предыдущего.

    from sklearn.model_selection import TimeSeriesSplit
    tscv = TimeSeriesSplit(n_splits=5)
    for train_index, val_index in tscv.split(X):
        # train_index всегда предшествует val_index по времени
  4. Leave-One-Out (LOO) Частный случай K-Fold, где K = N (число объектов). Каждый объект по очереди становится валидационным. Применяю очень редко из-за высокой вычислительной стоимости, только для очень маленьких датасетов (десятки образцов).

  5. Group K-Fold Когда применяю: Когда в данных есть группы, и нужно убедиться, что объекты из одной группы не попадут одновременно в train и test. Например, данные от нескольких пациентов в медицинском датасете или несколько снимков одного объекта.

    from sklearn.model_selection import GroupKFold
    groups = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5] # ID группы для каждого образца
    gkf = GroupKFold(n_splits=5)
    for train_index, val_index in gkf.split(X, y, groups=groups):
        # Объекты с одинаковым group_id не будут разбиты между фолдами

В 90% случаев для табличных данных я начинаю с Stratified K-Fold (shuffle=True) для классификации и обычного K-Fold для регрессии, если нет явной временной или групповой структуры.