Для чего нужен Grid Search?

Ответ

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

Как это работает: Вы определяете словарь, где ключи — это названия гиперпараметров (например, max_depth, n_estimators), а значения — списки возможных значений для перебора. Алгоритм обучает и оценивает модель для каждой возможной комбинации этих значений.

Пример с GridSearchCV из Scikit-learn для Random Forest:

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV, train_test_split
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)

# Определение модели и сетки параметров
model = RandomForestClassifier(random_state=42)
param_grid = {
    'n_estimators': [50, 100, 200],      # Количество деревьев
    'max_depth': [None, 10, 20, 30],     # Максимальная глубина дерева
    'min_samples_split': [2, 5, 10]      # Минимальное число образцов для разделения узла
}

# Создание и запуск Grid Search
grid_search = GridSearchCV(
    estimator=model,
    param_grid=param_grid,
    cv=5,               # 5-кратная кросс-валидация
    scoring='accuracy', # Метрика для оптимизации
    n_jobs=-1           # Использовать все ядра процессора
)
grid_search.fit(X_train, y_train)

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

# Оценка на тестовом наборе
best_model = grid_search.best_estimator_
test_score = best_model.score(X_test, y_test)
print(f"Accuracy на тестовом наборе: {test_score:.3f}")

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

Ответ 18+ 🔞

А, Grid Search, классика жанра! Ну, представь себе, что ты пытаешься подобрать идеальный рецепт самогона. У тебя есть куча параметров: сколько сахара сыпать, сколько дрожжей, какую температуру держать. И ты, вместо того чтобы делать на глаз, решаешь перебрать всё по списку, как самый упоротый перфекционист.

Вот Grid Search — это и есть тот самый дотошный мужик, который будет методично, блядь, варить самогон по каждой возможной комбинации из твоего списка. Две ложки сахара и одни дрожжи? Сделал. Три ложки и другие дрожжи? Сделал. Пока не перепробует всё, не успокоится. Цель — найти ту самую волшебную комбинацию, от которой модель на валидационных данных будет просто пизда рулю.

Как это выглядит в деле? Ты пишешь словарик, где говоришь: «Слушай, вот по этому параметру попробуй вот такие цифры, а по этому — вот такие». Алгоритм берёт этот список и начинает тупо, по-солдатски, гонять модель на каждой возможной паре, тройке, четвёрке значений. Овердохуища вычислений, конечно.

Вот смотри, как это в коде выглядит, на примере Random Forest. Ничего не трогаю, оставляю как есть, но объясню по-человечески.

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV, train_test_split
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)

# Создаём нашу модель — случайный лес.
model = RandomForestClassifier(random_state=42)
# А вот и наша сетка параметров, та самая инструкция для дотошного мужика.
param_grid = {
    'n_estimators': [50, 100, 200],      # Сколько деревьев в лесу попробовать
    'max_depth': [None, 10, 20, 30],     # Насколько глубоко каждое дерево может занырнуть
    'min_samples_split': [2, 5, 10]      # Сколько нужно образцов, чтобы узел решил splitнуться
}

# Создаём самого этого Grid Search.
grid_search = GridSearchCV(
    estimator=model,        # Модель, которую будем мучать
    param_grid=param_grid,  # Наша сетка параметров, тот самый словарик
    cv=5,                   # Кросс-валидация на 5 частей, чтобы не обмануться
    scoring='accuracy',     # Смотрим на accuracy, чтобы понять, кто круче
    n_jobs=-1               # Гони на всех ядрах, комп должен гореть!
)
# Запускаем этот адский перебор.
grid_search.fit(X_train, y_train)

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

# Берём лучшую модель и проверяем на тесте, который она не видела.
best_model = grid_search.best_estimator_
test_score = best_model.score(X_test, y_test)
print(f"Accuracy на тестовом наборе: {test_score:.3f}")

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

Минусы? Да охуеть можно от вычислительной сложности! Представь, у тебя не 3 параметра по 3 значения, а 10 параметров по 10 значений. Это же ёперный театр, сколько комбинаций-то будет? Комп будет считать до второго пришествия. Для непрерывных параметров — вообще пидарас шерстяной, ты же не все значения перечислишь.

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