W3docs

Поиск по сетке для настройки гиперпараметров в Python

Узнайте, как использовать GridSearchCV и RandomizedSearchCV в Python для настройки гиперпараметров моделей машинного обучения с примерами scikit-learn.

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

На этой странице рассматривается:

  • Что такое гиперпараметры и почему они важны
  • Как GridSearchCV выполняет полный перебор по сетке параметров
  • Как читать cv_results_ и понимать, что было протестировано
  • Использование n_jobs=-1 для параллельного выполнения поиска
  • RandomizedSearchCV как более быстрая альтернатива для больших сеток
  • Совмещение поиска по сетке с Pipeline для предотвращения утечки данных
  • Когда использовать поиск по сетке, а когда более быстрые альтернативы

Все примеры используют встроенные наборы данных scikit-learn, поэтому вы можете запустить их сразу.

Что такое гиперпараметры?

Каждая модель машинного обучения имеет два типа параметров:

  • Параметры модели обучаются автоматически во время тренировки (например, веса в нейронной сети, пороги разбиения в дереве решений).
  • Гиперпараметры задаются вами до начала обучения. Они управляют самим процессом обучения.

Неправильный выбор гиперпараметров может значительно снизить производительность способной модели. Например, дерево решений без ограничения глубины переобучится на тренировочных данных; дерево с ограничением глубины равным 1 окажется недообученным. Правильное значение зависит от ваших данных, и поиск по сетке находит его систематически, а не методом проб и ошибок.

Как работает GridSearchCV

GridSearchCV из scikit-learn объединяет две идеи:

  1. Перебор по сетке — генерируются все комбинации указанных вами значений гиперпараметров.
  2. Кросс-валидация — для каждой комбинации выполняется k-кратная кросс-валидация (см. Кросс-валидация в Python) и записывается средняя оценка.

После завершения поиска GridSearchCV сохраняет наилучшую комбинацию и автоматически переобучает модель с этими настройками на полном обучающем наборе.

Количество подгонок равно (количество комбинаций) × (число фолдов). Сетка с 3 × 3 × 3 = 27 комбинациями и cv=5 выполняет 135 подгонок — это приемлемо для быстрых моделей, но дорого для медленных.

Базовый пример GridSearchCV

В приведённом ниже примере выполняется настройка классификатора на основе дерева решений на наборе данных Iris.

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_iris

X, y = load_iris(return_X_y=True)

# Model with no hyperparameters set yet
model = DecisionTreeClassifier(random_state=42)

# Define the grid of values to try
param_grid = {
    'max_depth': [2, 3, 5, None],
    'min_samples_split': [2, 5, 10],
    'criterion': ['gini', 'entropy'],
}

# cv=5 means 5-fold cross-validation for each combination
grid_search = GridSearchCV(
    estimator=model,
    param_grid=param_grid,
    cv=5,
    scoring='accuracy',
    n_jobs=-1,       # use all CPU cores
    verbose=0,
)

grid_search.fit(X, y)

print("Best parameters:", grid_search.best_params_)
print("Best CV accuracy: {:.3f}".format(grid_search.best_score_))

Что делает каждый аргумент:

АргументНазначение
estimatorМодель для настройки. Подходит любой оценщик scikit-learn.
param_gridСловарь, сопоставляющий имена параметров со списками значений-кандидатов.
cvКоличество фолдов в кросс-валидации (5 — распространённое значение по умолчанию).
scoringМетрика для оптимизации. По умолчанию используется метод .score() оценщика.
n_jobsКоличество параллельных задач. -1 использует все доступные ядра CPU.

Типичный вывод:

Best parameters: {'criterion': 'gini', 'max_depth': 3, 'min_samples_split': 2}
Best CV accuracy: 0.967

Чтение cv_results_

После обучения grid_search.cv_results_ — это словарь массивов, по одной записи на каждую проверенную комбинацию. Наиболее полезные ключи:

import pandas as pd

results = pd.DataFrame(grid_search.cv_results_)

# Show top 5 combinations by mean test score
cols = ['param_max_depth', 'param_min_samples_split', 'param_criterion',
        'mean_test_score', 'std_test_score', 'rank_test_score']
print(results[cols].sort_values('rank_test_score').head(5).to_string(index=False))

Ключевые столбцы:

  • mean_test_score — среднее значение CV-оценки по всем фолдам для данной комбинации.
  • std_test_score — стандартное отклонение; высокое значение означает нестабильность оценки по фолдам.
  • rank_test_score — ранг 1 у победителя.

Варианты метрик оценки

По умолчанию GridSearchCV оптимизирует стандартную метрику оценщика. Можно указать любую встроенную метрику или пользовательскую:

# Common scoring strings
scoring_options = [
    'accuracy',       # classification
    'f1_weighted',    # F1 for multi-class
    'roc_auc',        # binary classification
    'neg_mean_squared_error',  # regression (note: negative so higher = better)
    'r2',             # regression
]

# Evaluate multiple metrics at once (refit on the one you care most about)
grid_search = GridSearchCV(
    estimator=DecisionTreeClassifier(random_state=42),
    param_grid={'max_depth': [2, 3, 5]},
    cv=5,
    scoring={'acc': 'accuracy', 'f1': 'f1_weighted'},
    refit='acc',       # use accuracy to pick the best model
    n_jobs=-1,
)

Использование Pipeline для предотвращения утечки данных

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

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import GridSearchCV

X, y = load_breast_cancer(return_X_y=True)

# Build a pipeline: scale then classify
pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('svc', SVC()),
])

# Reference pipeline steps with double-underscore: step__param
param_grid = {
    'svc__C': [0.1, 1, 10],
    'svc__kernel': ['linear', 'rbf'],
    'svc__gamma': ['scale', 'auto'],
}

grid_search = GridSearchCV(pipe, param_grid, cv=5, scoring='accuracy', n_jobs=-1)
grid_search.fit(X, y)

print("Best params:", grid_search.best_params_)
print("Best CV accuracy: {:.3f}".format(grid_search.best_score_))

Синтаксис с двойным подчёркиванием (svc__C) является ключевым: он указывает scikit-learn передать C шагу svc внутри пайплайна. Без пайплайна масштабирование всего набора данных до кросс-валидации привело бы к утечке информации из тестового фолда в масштабировщик, что дало бы излишне оптимистичную оценку.

RandomizedSearchCV: быстрее для больших сеток

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

from sklearn.model_selection import RandomizedSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from scipy.stats import randint

X, y = load_iris(return_X_y=True)

# Use distributions instead of discrete lists
param_dist = {
    'n_estimators': randint(50, 500),   # random integer in [50, 500)
    'max_depth': [3, 5, 10, None],
    'min_samples_split': randint(2, 20),
    'max_features': ['sqrt', 'log2'],
}

rand_search = RandomizedSearchCV(
    estimator=RandomForestClassifier(random_state=42),
    param_distributions=param_dist,
    n_iter=30,        # try 30 random combinations instead of all
    cv=5,
    scoring='accuracy',
    n_jobs=-1,
    random_state=42,
)

rand_search.fit(X, y)

print("Best params:", rand_search.best_params_)
print("Best CV accuracy: {:.3f}".format(rand_search.best_score_))

GridSearchCV vs RandomizedSearchCV:

GridSearchCVRandomizedSearchCV
Стратегия поискаПолный перебор (все комбинации)Случайная выборка
ВоспроизводимостьПолностью детерминированаЗадайте random_state
Лучше дляНебольших, чётко определённых сетокБольших пространств поиска
Непрерывные распределенияНе поддерживаютсяПоддерживаются через scipy.stats
Гарантия нахождения лучшегоДа (в пределах сетки)Нет, но часто близко

Для больших сеток RandomizedSearchCV с n_iter=50–100 нередко находит почти оптимальное решение за долю вычислительного времени.

Получение предсказаний с помощью лучшей модели

После обучения GridSearchCV ведёт себя как обычный оценщик. Атрибут best_estimator_ содержит переобученную модель:

from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_iris

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

param_grid = {'max_depth': [2, 3, 5], 'criterion': ['gini', 'entropy']}
grid_search = GridSearchCV(
    DecisionTreeClassifier(random_state=42),
    param_grid, cv=5, n_jobs=-1
)
grid_search.fit(X_train, y_train)

# Evaluate on the held-out test set
test_score = grid_search.score(X_test, y_test)
print("Test accuracy: {:.3f}".format(test_score))

# Access the best model directly
best_model = grid_search.best_estimator_
predictions = best_model.predict(X_test[:5])
print("Predictions for first 5 test samples:", predictions)

Важно: всегда держите отдельный отложенный тестовый набор, который никогда не используется во время поиска по сетке. Оценка кросс-валидации внутри GridSearchCV оценивает обобщаемость, но итоговая оценка должна производиться на данных, которые поиск никогда не видел.

Когда использовать поиск по сетке

Поиск по сетке является хорошим выбором по умолчанию, когда:

  • У вас небольшая или средняя модель, которая обучается быстро (секунды или несколько минут за подгонку).
  • Вы примерно знаете, какие гиперпараметры наиболее важны, и имеете разумный набор значений-кандидатов.
  • Воспроизводимость и полнота перебора важны.

Рассмотрите альтернативы, когда:

  • Сетка большая (много параметров с множеством значений) — сначала используйте RandomizedSearchCV для сужения пространства, затем уточните с помощью GridSearchCV.
  • Обучение дорогостоящее (глубокое обучение, большие ансамбли) — библиотеки байесовской оптимизации, такие как scikit-optimize или Optuna, делают более умные выборы, чем случайная выборка.
  • Нужна автоматическая остановка — стратегии уполовинивания (HalvingGridSearchCV) отсекают слабых кандидатов досрочно и требуют меньше суммарных подгонок.

Практические советы

  • Начинайте с грубой сетки. Используйте небольшую сетку со значениями, охватывающими порядки величин (например, C: [0.01, 0.1, 1, 10, 100]). Найдя перспективную область, уточните её более детальной сеткой.
  • Следите за стандартными отклонениями. Если std_test_score велико, модель чувствительна к конкретному разбиению данных. Рассмотрите увеличение cv или сбор большего объёма данных.
  • Устанавливайте n_jobs=-1, чтобы задействовать все ядра CPU — это ничего не стоит и часто даёт ускорение в 4–8 раз на современном компьютере.
  • Используйте Pipeline. Всегда оборачивайте предобработку и модель в Pipeline перед передачей в GridSearchCV. Это самая важная практика для получения надёжных оценок.
  • Используйте стратифицированные фолды для классификации. GridSearchCV автоматически применяет StratifiedKFold для классификаторов, что сохраняет пропорции классов по фолдам.

Связанные темы

Was this page helpful?