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

В практике машинного обучения мы часто сталкиваемся с ключевой проблемой: как оценить качество модели? Вы можете подумать об использовании части данных для обучения модели, а затем другой части невиданных данных для проверки её производительности. Эта идея совершенно верна, но как мы можем оценить модель более надёжно и стабильно? ЭтоПерекрёстная проверка— основная проблема, которую нужно решить.

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

Эта статья поможет вам глубоко понять принципы, распространённые методы и ключевую роль перекрёстной проверки в оптимизации моделей и инженерии.


Зачем нужна перекрёстная проверка?

Прежде чем углубляться в технические детали, давайте сначала поймём её необходимость с помощью аналогии.

Представьте, что вы студент, которому предстоит сдавать важный экзамен по математике. Существуют два метода оценки вашего уровня:

  • Метод A (простое разбиение): Учитель случайным образом выбирает 10 вопросов из банка заданий, чтобы вы прошли пробный экзамен, а затем использует этот результат для прогнозирования вашей итоговой оценки за экзамен.
  • Метод B (перекрёстная проверка): Учитель делит банк заданий на 5 частей. В первый раз используйте части 2, 3, 4, 5 для вашего обучения, а часть 1 — для тестирования; во второй раз используйте части 1, 3, 4, 5 для вашего обучения, а часть 2 — для тестирования... Повторите это 5 раз. Наконец, возьмите среднее из 5 результатов тестирования, чтобы оценить вас.

Какой метод более надёжен? Очевидно,Метод B。

  • Метод AРиск метода A заключается в следующем: если выбранные 10 вопросов окажутся типами, в которых вы сильны, результат пробного экзамена будет завышен, что приведёт к излишнему оптимизму относительно вашего истинного уровня; напротив, если выбранные вопросы окажутся вашими слепыми зонами, результат будет слишком низким, что приведёт к излишнему пессимизму. Результаты оценки сильно колеблются и нестабильны.
  • Метод BБлагодаря множеству различных комбинаций обучения/тестирования он позволяет вам познакомиться с различными типами вопросов в банке вопросов, а полученная средняя оценка более репрезентативна для вашего общего, стабильного уровня и позволяет точнее предсказать результат итогового экзамена.

В машинном обучении:

  • банк вопросов— это нашполный набор данных。
  • студент— это модель, которую мы хотим обучить,модель машинного обучения。
  • оценка за пробный экзамен— этометрика оценки модели(например, точность, среднеквадратичная ошибка и т. д.).
  • итоговый экзамен— это будущаяпроизводительность модели на реальных, не встречавшихся ранее данных.

Основная цель кросс-валидации — обеспечить для способности модели к обобщениюболее устойчивую и более несмещённую оценку, тем самым помогая нам выполнять более надёжный выбор модели, настройку параметров и оценку производительности.


Распространённые методы кросс-валидации

Кросс-валидация имеет несколько методов реализации, подходящих для разных данных и сценариев. Ниже представлены наиболее распространённые из них.

1. Отложенная валидация

Это самый простой и интуитивно понятный метод.

Пример

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# Создаём данные для запуска
# 200 образцов, 4 признака, бинарная классификация
np.random.seed(42)
X = np.random.randn(200, 4)
y = (X[:, 0] + X[:, 1] * 0.7 - X[:, 2] * 0.4 > 0).astype(int)

# 1. Разделение обучающей и тестовой выборок (7:3)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)

# 2. Обучение модели
model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)

# 3. Оценка на тестовой выборке
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)

print(f"Точность модели: {accuracy:.4f}")

Результат вывода:

模型准确率: 0.8833

Описание процесса:

  • Advantages:Простота и скорость, низкие вычислительные затраты.

  • Недостатки:Результат оценки сильно зависит от одного случайного разбиения. Если разбиение неудачное, результат оценки может быть нерепрезентативным. При этом, поскольку тестовый набор используется только один раз, данные используются недостаточно эффективно.

2. K-фолдовая кросс-валидация

В настоящее время это наиболее часто используемый и стандартный метод кросс-валидации.

Принцип:Разделить набор данныхравномернослучайным образом на K взаимоисключающих подмножеств (называемых фолдами).

В каждом эксперименте по очереди используйте одно подмножество в качестве тестового набора, а остальные K-1 подмножеств — в качестве обучающего набора. Этот процесс повторяется K раз, гарантируя, что каждое подмножество один раз используется как тестовый набор. В итоге мы получаем K оценок и берём их среднее как финальную оценку производительности модели.

Пример

import numpy as np
from sklearn.model_selection import cross_val_score, KFold
from sklearn.linear_model import LogisticRegression

# Создать примерные данные для запуска
# 100 образцов, 4 признака, метки бинарной классификации
np.random.seed(42)
X = np.random.randn(100, 4)
y = (X[:, 0] + X[:, 1] * 0.5 > 0).astype(int)

# 1. Инициализация модели
model = LogisticRegression(max_iter=1000)

# 2. Определить разделитель K-фолдовой кросс-валидации (K=5)
kfold = KFold(n_splits=5, shuffle=True, random_state=42)

# 3. Выполнить кросс-валидацию
scores = cross_val_score(model, X, y, cv=kfold, scoring='accuracy')

print(f"Точность по фолдам: {scores}")
print(f"Средняя точность: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})")
每次折叠的准确率: [0.9  0.95 1.   0.95 1.  ]
平均准确率: 0.9600 (+/- 0.0748)

Схема процесса при K=5:

Как выбрать значение K?

  • Распространённые значения: 5 или 10. Это эмпирический компромисс.
  • Меньшее значение K (например, 3): обучающая выборка больше, но число оценок невелико, и дисперсия оценки может быть большой.
  • Большее значение K (например, 10 или 20): оценка более стабильна (малая дисперсия), но обучающая выборка каждый раз ближе к исходному набору данных, что может внести более оптимистичное смещение оценки, а вычислительные затраты значительно возрастают.
  • Крайний случай K = N (число примеров): это leave-one-out, тестирование каждый раз только на одном примере. Оценка наиболее несмещённая, но вычислительные затраты чрезвычайно высоки; обычно используется только для очень малых наборов данных.

Преимущества:данные используются полностью, а результаты оценки стабильны и надёжны.

Недостатки:вычислительные затраты в K раз выше, чем у метода hold-out.

3. Стратифицированная K-фолдовая кросс-валидация

Это важный вариант K-фолдовой кросс-валидации, особенно подходящий длязадач классификацииСреднийс несбалансированным распределением классовнаборов данных.

Решаемая проблема:В обычной K-фолдовой кросс-валидации случайное разбиение может привести к тому, что доля определённого класса в некоторых фолдах будет сильно отличаться от исходного набора данных. Например, если в наборе данных 90% положительного класса и 10% отрицательного класса, случайное разбиение на 5 фолдов может дать фолд, полностью состоящий из положительного класса, без отрицательного класса, что делает оценку на этом фолде бессмысленной.

Стратифицированная K-фолдовая кросс-валидация гарантирует, что при разбиении доля образцов каждого класса в каждом фолде остаётся согласованной с общей долей в исходном наборе данных.

Пример

from sklearn.model_selection import StratifiedKFold, cross_val_score

# Использование почти такое же, как у KFold, только замените разделитель
stratified_kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=stratified_kfold, scoring='accuracy')

Для задач классификации, особенно когда классы несбалансированы,отдавайте предпочтение использованиюStratifiedKFold。

4. Разделение временных рядов

Дляданных временных рядов, порядок данных критически важен (данные завтрашнего дня зависят от сегодняшних и вчерашних). Мы не можем случайно перемешивать данные; мы должны сохранять временной порядок.

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

Пример

import numpy as np
from sklearn.model_selection import TimeSeriesSplit

# Создание запускаемых данных временного ряда
# 100 временных точек, 2 признака
np.random.seed(42)
X = np.random.randn(100, 2)

# Пример TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)

for train_index, test_index in tscv.split(X):
    print(f"Диапазон индексов обучающего набора: {train_index)
    print(f"Диапазон индексов тестового набора: {test_index)
    print("---")

Вывод:

训练集索引范围: 0 到 19
测试集索引范围: 20 到 35
---
训练集索引范围: 0 到 35
测试集索引范围: 36 到 51
---
训练集索引范围: 0 到 51
测试集索引范围: 52 到 67
---
训练集索引范围: 0 到 67
测试集索引范围: 68 到 83
---
训练集索引范围: 0 到 83
测试集索引范围: 84 到 99
---

Применение кросс-валидации в инженерии моделей

Кросс-валидация — это не только инструмент оценки, но и ключевая часть процесса оптимизации и инженерии моделей.

Применение 1: Выбор и сравнение моделей

Когда нам нужно выбрать среди нескольких моделей-кандидатов (таких как линейная регрессия, дерево решений, машина опорных векторов), мы не можем использовать тестовый набор для выбора (иначе тестовый набор становится частью процесса обучения и происходит "утечка" информации). Правильный подход таков:

  1. Для каждой модели-кандидата наобучающем набореиспользуйте кросс-валидацию, чтобы получить оценку её производительности.
  2. Сравните средние оценки этих результатов кросс-валидации и выберите модель с наивысшей оценкой.
  3. Наконец, переобучите выбранную модель на всём обучающем наборе и используйтенезависимый тестовый набор, чтобы выполнить финальную однократную оценку, указав эту оценку в качестве итоговой производительности модели.

Пример

import numpy as np
from sklearn.model_selection import cross_val_score, StratifiedKFold, train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier

# Создайте запускаемые данные для классификации
# 200 образцов, 4 признака, бинарная классификация
np.random.seed(42)
X = np.random.randn(200, 4)
y = (X[:, 0] + X[:, 1] * 0.8 - X[:, 2] * 0.3 > 0).astype(int)

# Разделите обучающий набор / тестовый набор
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42, stratify=y
)

# Определите модели
models = {
    'Logistic Regression': LogisticRegression(max_iter=1000),
    'SVM': SVC(),
    'Decision Tree': DecisionTreeClassifier()
}

# Стратифицированная K-кратная кросс-валидация
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
results = {}

# Оценка с помощью кросс-валидации
for name, model in models.items():
    scores = cross_val_score(model, X_train, y_train, cv=cv, scoring='accuracy')
    results[name] = scores.mean()
    print(f"{name} средняя точность: {scores.mean():.4f}")

# Выбор лучшей модели
best_model_name = max(results, key=results.get)
print(f"\nПо результатам кросс-валидации лучшая модель: {best_model_name}")

# Финальное обучение и оценка на тестовой выборке
best_model = models[best_model_name]
best_model.fit(X_train, y_train)
final_score = best_model.score(X_test, y_test)
print(f"Итоговая точность лучшей модели на независимом тестовом наборе: {final_score:.4f}")

Вывод:

Logistic Regression 平均准确率: 0.9533
SVM 平均准确率: 0.9400
Decision Tree 平均准确率: 0.8467

根据交叉验证,最佳模型是: Logistic Regression
最佳模型在独立测试集上的最终准确率: 1.0000

Приложение 2: Настройка гиперпараметров

Гиперпараметры — это параметры, которые необходимо задать перед обучением модели (например, количество деревьев в случайном лесуn_estimators, штрафной коэффициент SVMC). Процесс поиска наилучшей комбинации гиперпараметров называетсянастройкой гиперпараметров, а кросс-валидация — его стандартным методом оценки.

Наиболее часто используемый метод — этокросс-валидация с поиском по сетке。

Пример

import numpy as np
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.ensemble import RandomForestClassifier

# Создайте запускаемые данные для классификации
# 300 образцов, 5 признаков, бинарная классификация
np.random.seed(42)
X = np.random.randn(300, 5)
y = (X[:, 0] * 0.6 + X[:, 1] * 0.4 - X[:, 2] > 0).astype(int)

# Разделите обучающий набор / тестовый набор
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42, stratify=y
)

# 1. Сетка параметров
param_grid = {
    'n_estimators': [50, 100, 200],
    'max_depth': [None, 10, 20],
    'min_samples_split': [2, 5, 10]
}

# 2. Базовая модель
rf = RandomForestClassifier(random_state=42)

# 3. GridSearchCV
grid_search = GridSearchCV(
    estimator=rf,
    param_grid=param_grid,
    cv=5,
    scoring='accuracy',
    n_jobs=-1
)

# 4. Поиск по сетке (только обучающая выборка)
grid_search.fit(X_train, y_train)

# 5. Оптимальные параметры и оценка
print(f"Лучшие параметры: {grid_search.best_params_}")
print(f"Лучшая оценка кросс-валидации: {grid_search.best_score_:.4f}")

# 6. Оценка на тестовой выборке
best_rf_model = grid_search.best_estimator_
test_accuracy = best_rf_model.score(X_test, y_test)
print(f"Точность настроенной модели на тестовой выборке: {test_accuracy:.4f}")

Вывод:

最佳参数: {'max_depth': None, 'min_samples_split': 2, 'n_estimators': 100}
最佳交叉验证分数: 0.9067
调优后模型在测试集上的准确率: 0.9467

Ключевые моменты: GridSearchCVВнутри кросс-валидация уже завершена. Она дополнительно разбивает обучающую выборкуX_trainна меньшие "обучающие подмножества" и "валидационные подмножества", чтобы оценить параметры, поэтому то, что мы передаём,X_trainэквивалентно всему "банку вопросов", тогда какX_test— это «окончательный экзаменационный вопрос», который никогда не участвовал в процессе настройки и используется для финальной проверки.


Практические упражнения и резюме

Практическое упражнение

  1. Базовая реализация: Используйтеsklearnвстроенный набор данных Iris, соответственно используяtrain_test_splitиcross_val_score(K=5) для обучения и оценкиKNeighborsClassifier, и сравнить показатели, полученные двумя методами оценки.
  2. Сравнение моделей: На одном и том же наборе данных используйте кросс-валидацию, чтобы сравнитьSVC、RandomForestClassifierиGradientBoostingClassifierпроизводительность моделей.
  3. Настройка параметров: ДляSVCмодели составьте сетку параметров (включаяCиgamma), используйтеGridSearchCVчтобы найти оптимальные параметры.

Сводка ключевых моментов

  • Цель кросс-валидации: получить более устойчивую и надёжную оценку способности модели к обобщению.
  • Основной метод:K-кратная кросс-валидацияявляется золотым стандартом; для задач классификации отдавайте предпочтение использованиюстратифицированной K-кратной кросс-валидации。
  • Ключевое различие:
    • Обучающая выборка/валидационная выборка: Используется для обучения модели иоценки в процессе разработки(например, выбора моделей, настройки параметров). Кросс-валидация происходит на этом этапе.
    • Тестовый набор: Только после завершения всей разработки используется дляитогового однократного отчёта о производительности. Он должен быть строго изолирован и никогда не использоваться для принятия каких-либо решений.
  • Инженерная роль: Кросс-валидация — это мост, соединяющий разработку модели (обучение, настройку) и оценку модели (тестирование), и краеугольный камень для обеспечения качества модели, предотвращения переобучения и достижения надёжного выбора и оптимизации модели.
Другие расширения