scikit-learnMiddleCoding
Как работает GridSearchCV и чем он отличается от RandomizedSearchCV?
GridSearchCV перебирает все комбинации гиперпараметров (n_candidates = произведение длин), RandomizedSearchCV сэмплирует n_iter случайных — выгоднее при большом пространстве поиска.
GridSearchCV vs RandomizedSearchCV
GridSearchCV строит декартово произведение всех значений параметров и обучает модель на каждой комбинации с k-fold CV. Если у вас 3 параметра по 5 значений каждый и cv=5, это 5³ × 5 = 625 обучений. RandomizedSearchCV сэмплирует ровно n_iter случайных точек из пространства поиска, что даёт предсказуемый бюджет вычислений.
Когда выбирать
- GridSearchCV — пространство параметров маленькое и все комбинации имеют смысл (например, 2-3 параметра, каждый по 3-4 значения).
- RandomizedSearchCV — широкое пространство, непрерывные распределения (
loguniform,uniform), или бюджет времени ограничен.
Пример с GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.datasets import make_classification
import numpy as np
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
pipeline = Pipeline([
("scaler", StandardScaler()),
("svc", SVC(probability=True)),
])
# Имена параметров: <step_name>__<param_name>
param_grid = {
"svc__C": [0.1, 1.0, 10.0],
"svc__kernel": ["rbf", "linear"],
"svc__gamma": ["scale", "auto"],
} # 3 * 2 * 2 = 12 комбинаций, cv=5 -> 60 обучений
grid_search = GridSearchCV(
pipeline,
param_grid,
cv=5,
scoring="roc_auc",
n_jobs=-1,
verbose=1,
refit=True, # переобучает лучшую модель на всём train
)
grid_search.fit(X_train, y_train)
print("Best params:", grid_search.best_params_)
print("Best CV ROC-AUC:", grid_search.best_score_)
print("Test ROC-AUC:", grid_search.score(X_test, y_test))
Пример с RandomizedSearchCV
from sklearn.model_selection import RandomizedSearchCV
from sklearn.ensemble import GradientBoostingClassifier
from scipy.stats import loguniform, randint
pipeline2 = Pipeline([
("scaler", StandardScaler()),
("gb", GradientBoostingClassifier(random_state=42)),
])
# Можно использовать scipy-распределения — GridSearchCV так не умеет
param_dist = {
"gb__n_estimators": randint(50, 300),
"gb__learning_rate": loguniform(1e-3, 0.5),
"gb__max_depth": randint(2, 8),
"gb__subsample": [0.6, 0.8, 1.0],
}
rand_search = RandomizedSearchCV(
pipeline2,
param_distributions=param_dist,
n_iter=30, # фиксированный бюджет: 30 * cv=5 = 150 обучений
cv=5,
scoring="roc_auc",
n_jobs=-1,
random_state=42, # воспроизводимость
refit=True,
)
rand_search.fit(X_train, y_train)
print("Best params:", rand_search.best_params_)
print("Best CV ROC-AUC:", rand_search.best_score_)
# Анализ результатов
import pandas as pd
results = pd.DataFrame(rand_search.cv_results_)
print(results[["param_gb__learning_rate", "param_gb__n_estimators",
"mean_test_score", "std_test_score"]]
.sort_values("mean_test_score", ascending=False)
.head(5))
Halving-варианты (scikit-learn >= 1.0)
Для экономии времени используйте HalvingGridSearchCV и HalvingRandomSearchCV: они отсекают слабые кандидаты на ранних итерациях, выделяя больше ресурсов перспективным:
from sklearn.model_selection import HalvingRandomSearchCV
halving = HalvingRandomSearchCV(
pipeline2,
param_dist,
factor=3, # каждый раунд оставляет 1/3 кандидатов
cv=5,
scoring="roc_auc",
random_state=42,
n_jobs=-1,
)
halving.fit(X_train, y_train)
Подводные камни
- Передача
X_testвfitвместоX_train— leakage;GridSearchCVне предупредит, просто оценит слишком оптимистично. - Параметры Pipeline задаются через
step__param; опечатка в имени шага не вызывает ошибку доfit, а иногда молча игнорируется. refit=True(дефолт) переобучает на всёмX_train; если нужна внешняя финальная оценка, передайтеX_testтолько послеbest_estimator_.n_jobs=-1+Pipeline+ Windows = проблемы сmultiprocessing; на Linux работает надёжно.- При использовании
loguniformиз scipy минимальное значение не может быть 0 — передайтеloguniform(1e-5, 1), иначеValueError. cv_results_['mean_test_score']— это среднее по CV-фолдам, не метрика на holdout; не путать.RandomizedSearchCVс маленькимn_iterможет не покрыть хорошую область пространства — увеличивайте итерации или уменьшайте пространство поиска.- Кастомный scorer через
make_scorerдолжен возвращать float (выше = лучше); знак инвертируется автоматически только для некоторых метрик.
Common mistakes
- Объяснять
gridsearch vs randomizedsearchтолько синтаксисом без shape, dtype, состояния или режима выполнения. - Игнорировать leakage, воспроизводимость, пустые входы и скрытые копии данных.
- Не проверять production-симптомы: latency, память, ретраи, дрейф качества и несовпадение версий.
What the interviewer is testing
- Может ли связать
gridsearch vs randomizedsearchс реальным контрактом входов и выходов. - Упоминает ли тесты, метрики, reproducibility и диагностику ошибок.
- Видит ли различие между demo-кодом в ноутбуке и production-пайплайном.