Búsqueda en Cuadrícula para Ajuste de Hiperparámetros en Python
Aprende a usar GridSearchCV y RandomizedSearchCV en Python para ajustar hiperparámetros de modelos de machine learning con ejemplos de scikit-learn.
El ajuste de hiperparámetros es el proceso de encontrar los valores de configuración de un modelo de machine learning que no se aprenden a partir de los datos — cosas como la profundidad de un árbol de decisión, la intensidad de regularización de una regresión logística, o el número de neuronas en una red neuronal. La búsqueda en cuadrícula es el enfoque más sencillo: define un conjunto discreto de valores para cada hiperparámetro, prueba cada combinación y quédate con la mejor.
Esta página cubre:
- Qué son los hiperparámetros y por qué importan
- Cómo
GridSearchCVrealiza una búsqueda exhaustiva en una cuadrícula de parámetros - Cómo leer
cv_results_y entender qué se probó - Usar
n_jobs=-1para paralelizar la búsqueda RandomizedSearchCVcomo alternativa más rápida para cuadrículas grandes- Combinar la búsqueda en cuadrícula con un
Pipelinepara evitar la fuga de datos - Cuándo usar la búsqueda en cuadrícula frente a alternativas más rápidas
Todos los ejemplos utilizan los conjuntos de datos integrados de scikit-learn, por lo que puedes ejecutarlos de inmediato.
¿Qué Son los Hiperparámetros?
Cada modelo de machine learning tiene dos tipos de parámetros:
- Los parámetros del modelo se aprenden automáticamente durante el entrenamiento (por ejemplo, los pesos en una red neuronal, los umbrales de división en un árbol de decisión).
- Los hiperparámetros los configuras tú antes de que comience el entrenamiento. Controlan el proceso de aprendizaje en sí.
Elegir los hiperparámetros incorrectos puede dejar a un modelo capaz con un rendimiento muy por debajo de su potencial. Por ejemplo, un árbol de decisión sin límite de profundidad sobreajustará los datos de entrenamiento; uno con un límite de profundidad de 1 tendrá un ajuste insuficiente. El límite correcto depende de tus datos, y la búsqueda en cuadrícula lo encuentra de forma sistemática en lugar de por intuición.
Cómo Funciona GridSearchCV
GridSearchCV de scikit-learn combina dos ideas:
- Enumeración de la cuadrícula — genera cada combinación de los valores de hiperparámetros que especificas.
- Validación cruzada — para cada combinación realiza una validación cruzada k-fold (consulta Validación Cruzada en Python) y registra la puntuación media.
Tras la búsqueda, GridSearchCV almacena la mejor combinación y ajusta automáticamente un modelo con esa configuración sobre el conjunto de entrenamiento completo.
El número de ajustes es (combinaciones) × (pliegues de cv). Una cuadrícula con 3 × 3 × 3 = 27 combinaciones y cv=5 ejecuta 135 ajustes — manejable para modelos rápidos, costoso para los lentos.
Ejemplo Básico de GridSearchCV
El siguiente ejemplo ajusta un Clasificador de Árbol de Decisión sobre el conjunto de datos 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_))Qué hace cada argumento:
| Argumento | Propósito |
|---|---|
estimator | El modelo a ajustar. Funciona con cualquier estimador de scikit-learn. |
param_grid | Diccionario que mapea nombres de parámetros a listas de valores candidatos. |
cv | Número de pliegues en la validación cruzada (5 es el valor predeterminado habitual). |
scoring | Métrica a optimizar. Por defecto usa el método .score() del estimador. |
n_jobs | Número de trabajos en paralelo. -1 usa todos los núcleos de CPU disponibles. |
Salida típica:
Best parameters: {'criterion': 'gini', 'max_depth': 3, 'min_samples_split': 2}
Best CV accuracy: 0.967Lectura de cv_results_
Después del ajuste, grid_search.cv_results_ es un diccionario de arrays — una entrada por cada combinación probada. Las claves más útiles son:
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))Columnas clave:
mean_test_score— la puntuación de CV media en todos los pliegues para esa combinación.std_test_score— desviación estándar; un valor alto significa que la puntuación es inestable entre pliegues.rank_test_score— el rango 1 es el ganador.
Opciones de Puntuación
Por defecto, GridSearchCV optimiza la métrica predeterminada del estimador. Puedes especificar cualquier puntuador integrado o uno personalizado:
# 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,
)Usar un Pipeline para Prevenir la Fuga de Datos
Cuando tu preprocesamiento depende de los datos de entrenamiento (escalado, imputación, selección de características), debes ajustar el preprocesador únicamente en los pliegues de entrenamiento — nunca en el conjunto de datos completo antes de dividirlo. Un Pipeline gestiona esto automáticamente y funciona sin problemas con 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_))La sintaxis de doble guión bajo (svc__C) es la clave: le indica a scikit-learn que pase C al paso svc dentro del pipeline. Sin un pipeline, escalar el conjunto de datos completo antes de la validación cruzada filtraría información del pliegue de prueba al escalador, generando una puntuación demasiado optimista.
RandomizedSearchCV: Más Rápido para Cuadrículas Grandes
La búsqueda en cuadrícula exhaustiva se vuelve impracticable cuando cada hiperparámetro tiene muchos valores candidatos. RandomizedSearchCV muestrea un número fijo de combinaciones aleatorias en lugar de probarlas todas:
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:
GridSearchCV | RandomizedSearchCV | |
|---|---|---|
| Estrategia de búsqueda | Exhaustiva (todas las combinaciones) | Muestreo aleatorio |
| Reproducibilidad | Totalmente determinista | Establecer random_state |
| Mejor para | Cuadrículas pequeñas y bien definidas | Espacios de búsqueda grandes |
| Distribuciones continuas | No compatible | Compatible mediante scipy.stats |
| Garantiza encontrar el mejor | Sí (dentro de la cuadrícula) | No, pero suele estar cerca |
Para cuadrículas grandes, RandomizedSearchCV con n_iter=50–100 frecuentemente encuentra una solución casi óptima en una fracción del tiempo de cómputo.
Hacer Predicciones con el Mejor Modelo
Después del ajuste, GridSearchCV actúa como un estimador normal. Su atributo best_estimator_ contiene el modelo reajustado:
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)Importante: mantén siempre un conjunto de prueba separado que nunca se vea durante la búsqueda en cuadrícula. La puntuación de validación cruzada dentro de GridSearchCV estima la generalización, pero la evaluación final verdadera debe realizarse sobre datos que la búsqueda nunca tocó.
Cuándo Usar la Búsqueda en Cuadrícula
La búsqueda en cuadrícula es una opción sólida por defecto cuando:
- Tienes un modelo pequeño o mediano que entrena rápidamente (segundos a pocos minutos por ajuste).
- Sabes aproximadamente qué hiperparámetros son los más importantes y tienes un conjunto sensato de valores candidatos.
- La reproducibilidad y la exhaustividad son importantes.
Considera alternativas cuando:
- La cuadrícula es grande (muchos parámetros con muchos valores) — usa
RandomizedSearchCVprimero para reducir el espacio y luego refina conGridSearchCV. - El entrenamiento es costoso (aprendizaje profundo, ensambles grandes) — las bibliotecas de optimización bayesiana como
scikit-optimizeoOptunatoman decisiones más inteligentes que el muestreo aleatorio. - Quieres parada automática — las estrategias de reducción progresiva (
HalvingGridSearchCV) eliminan a los candidatos con bajo rendimiento de forma temprana y requieren menos ajustes en total.
Consejos Prácticos
- Empieza con una cuadrícula gruesa. Usa una cuadrícula pequeña con valores distribuidos en órdenes de magnitud (por ejemplo,
C: [0.01, 0.1, 1, 10, 100]). Una vez que encuentres una región prometedora, refina con una cuadrícula más fina. - Observa las desviaciones estándar. Si
std_test_scorees grande, el modelo es sensible a la partición de datos concreta. Considera aumentarcvo recopilar más datos. - Establece
n_jobs=-1para usar todos los núcleos de CPU — no tiene ningún coste y a menudo proporciona una aceleración de 4 a 8 veces en una máquina moderna. - Combínalo con un Pipeline. Envuelve siempre el preprocesamiento y el modelo juntos en un
Pipelineantes de pasarlo aGridSearchCV. Esta es la práctica más importante para obtener puntuaciones fiables. - Usa pliegues estratificados para clasificación.
GridSearchCVutilizaStratifiedKFoldautomáticamente para clasificadores, lo que preserva las proporciones de clases en todos los pliegues.
Temas Relacionados
- Validación Cruzada en Python — comprende la evaluación k-fold que impulsa a
GridSearchCV - Clasificador de Árbol de Decisión — un modelo habitual para ajustar con búsqueda en cuadrícula
- Regresión Logística — otro modelo rápido muy adecuado para la búsqueda en cuadrícula
- K-Vecinos Más Cercanos —
n_neighborsymetricson objetivos clásicos de búsqueda en cuadrícula - Regresión Lineal — ajuste de hiperparámetros para variantes de regresión regularizada