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

Ответ

В зависимости от структуры данных и задачи я выбираю разные стратегии кросс-валидации (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 для регрессии, если нет явной временной или групповой структуры.

Ответ 18+ 🔞

Ну вот, сидишь ты такой, выбираешь, как модель проверить, чтобы потом не охуеть от результатов на реальных данных. Тут, блядь, целая наука, но если по-простому, то есть несколько проверенных способов, и каждый — под свою задачу. Слушай сюда.

Как я обычно кросс-валидацию кручу, чтобы не облажаться:

  1. Обычный K-Fold (K-кратная) Это как стандартный инструмент в ящике. Берёшь, если данные обычные, независимые, и все объекты друг на друга не влияют. Просто мешаешь их как карты и режешь на 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 (Стратифицированная) Включаю, когда делаю классификацию, а классы в данных разной численности — один овердохуища, а другой — кот наплакал. Эта штука следит, чтобы в каждом фолде пропорции классов были как в исходнике, иначе оценка метрик будет пиздец какая нестабильная.

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

    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) Это когда каждый объект по очереди становится тестовым. Использую раз в пятилетку, только если датасет микроскопический, человек на двадцать. Потому что считать это — ебать мои старые костыли, комп взвоет.

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

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

Если в двух словах, то в 90% случаев для табличных данных я стартую с Stratified K-Fold (с перемешиванием) для классификации и с обычного K-Fold для регрессии. Но если чувствую подвох — временную зависимость или группы — сразу переключаюсь на специализированные методы. Иначе потом сам от себя охуеешь, когда модель в продакшене накроется медным тазом.