Machine Learning Academy · Lección

Validación cruzada y búsqueda en cuadrícula de un pipeline completo

Pasará un Pipeline a cross_val_score y GridSearchCV, utilizando la notación de doble guion bajo para especificar los hiperparámetros de cada paso.

Lección 3 de 413 pasos

Validación cruzada y búsqueda en cuadrícula de un pipeline completo es una lección gratuita de Machine Learning Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Machine Learning Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Machine Learning Academy incluye 4 lecciones en total.

Partes de esta lección aún no han sido traducidas y se muestran en inglés.

Why Grid-Search a Full Pipeline?

Hyperparameter tuning should always be combined with cross-validation to prevent overfitting the validation set. When your preprocessing steps have their own parameters (e.g., PCA's n_components, OneHotEncoder's drop), those must be tuned simultaneously with the model's parameters. Wrapping everything in a Pipeline and passing it to GridSearchCV ensures all of this is done correctly without leakage.

Passing a Pipeline to cross_val_score

The simplest way to evaluate a Pipeline fairly is cross_val_score(pipeline, X, y, cv=5). Each fold re-fits the entire pipeline — including scaler and classifier — on the training portion, then evaluates on the held-out fold. The mean and standard deviation of the returned array give you a reliable generalisation estimate.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_wine
import numpy as np

X, y = load_wine(return_X_y=True)

pipe = Pipeline([
    ('sc', StandardScaler()),
    ('lr', LogisticRegression(C=1.0, max_iter=300))
])

scores = cross_val_score(pipe, X, y, cv=5, scoring='accuracy')
print(f'CV accuracy: {np.mean(scores):.4f} +/- {np.std(scores):.4f}')

Double-Underscore Notation for Pipeline Params

To reference a parameter of a named step inside the pipeline, use stepname__paramname. For nested structures like ColumnTransformer inside a Pipeline, chain the names: preprocessor__num__scaler__with_std. This convention is used both in set_params calls and in the param_grid dictionary passed to GridSearchCV.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC

pipe = Pipeline([('sc', StandardScaler()), ('svm', SVC())])

# Print all tunable parameters
params = pipe.get_params()
for k, v in params.items():
    print(f'  {k}: {v}')

Defining a param_grid for GridSearchCV

Create a dictionary where keys are pipeline parameter names (using double-underscore notation) and values are lists of candidates to try. GridSearchCV trains and evaluates the pipeline for every combination in the Cartesian product of all lists. The total number of fits equals len(combinations) * cv_folds.

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

X, y = load_wine(return_X_y=True)

pipe = Pipeline([('sc', StandardScaler()), ('svm', SVC())])

param_grid = {
    'svm__C': [0.1, 1.0, 10.0, 100.0],
    'svm__kernel': ['rbf', 'linear'],
    'svm__gamma': ['scale', 'auto']
}

grid = GridSearchCV(pipe, param_grid, cv=5, n_jobs=-1, scoring='accuracy')
grid.fit(X, y)
print('Best params:', grid.best_params_)
print('Best CV score:', grid.best_score_.round(4))

Tuning Preprocessor Parameters Too

You can include preprocessor parameters in the same grid. For example, tune n_components of a PCA step alongside the classifier's regularisation. This finds the optimal compression level and model complexity simultaneously, which is more rigorous than tuning them in separate steps.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_digits

X, y = load_digits(return_X_y=True)

pipe = Pipeline([
    ('sc', StandardScaler()),
    ('pca', PCA()),
    ('lr', LogisticRegression(max_iter=500))
])

param_grid = {
    'pca__n_components': [10, 20, 30, 40],
    'lr__C': [0.1, 1.0, 10.0]
}

grid = GridSearchCV(pipe, param_grid, cv=5, n_jobs=-1)
grid.fit(X, y)
print('Best:', grid.best_params_)
print('Score:', grid.best_score_.round(4))

Inspecting GridSearchCV Results

The cv_results_ attribute is a dictionary (convertible to a DataFrame) containing mean test scores, standard deviations, and fit times for every hyperparameter combination. Inspecting this DataFrame helps you understand the performance landscape and identify whether the best result is significantly better than the second-best, or if many parameter combinations perform similarly.

import pandas as pd

results = pd.DataFrame(grid.cv_results_)
results_sorted = results.sort_values('rank_test_score')
print(results_sorted[['param_pca__n_components', 'param_lr__C',
                       'mean_test_score', 'std_test_score']].head(6).to_string())

RandomizedSearchCV for Large Parameter Spaces

When the parameter space is large, GridSearchCV becomes computationally prohibitive. RandomizedSearchCV samples a fixed number of combinations at random (controlled by n_iter), often finding near-optimal results in a fraction of the time. Use scipy.stats distributions for continuous parameters to sample from a range rather than discrete values.

from sklearn.model_selection import RandomizedSearchCV
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.datasets import load_wine
from scipy.stats import loguniform, uniform

X, y = load_wine(return_X_y=True)

pipe = Pipeline([('sc', StandardScaler()), ('svm', SVC())])

param_dist = {
    'svm__C': loguniform(0.01, 100),
    'svm__gamma': loguniform(1e-4, 1),
    'svm__kernel': ['rbf', 'linear']
}

rs = RandomizedSearchCV(pipe, param_dist, n_iter=30, cv=5, random_state=42, n_jobs=-1)
rs.fit(X, y)
print('Best params:', rs.best_params_)
print('Best score:', rs.best_score_.round(4))

Nested CV: Evaluation and Selection Together

Standard grid search with cross-validation slightly overfits the validation set — after choosing the best hyperparameters, you have implicitly used the validation data. Nested cross-validation solves this: the outer loop evaluates the tuned model's generalisation, the inner loop selects hyperparameters. The outer loop score is an unbiased estimate of the final model's true test performance.

from sklearn.model_selection import GridSearchCV, cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.datasets import load_iris
import numpy as np

X, y = load_iris(return_X_y=True)

pipe = Pipeline([('sc', StandardScaler()), ('svm', SVC())])
param_grid = {'svm__C': [0.1, 1.0, 10.0], 'svm__gamma': ['scale', 'auto']}

inner_cv = GridSearchCV(pipe, param_grid, cv=5, n_jobs=-1)
# Outer CV evaluates the tuning procedure itself
outer_scores = cross_val_score(inner_cv, X, y, cv=5)
print(f'Nested CV score: {np.mean(outer_scores):.4f} +/- {np.std(outer_scores):.4f}')

Using the Best Estimator

After GridSearchCV.fit, the best_estimator_ attribute is the pipeline re-fitted on the entire training dataset using the best hyperparameters. This is the model you should use for final predictions. You can call predict, predict_proba, or score on it directly.

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 load_wine

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

pipe = Pipeline([('sc', StandardScaler()), ('svm', SVC())])
param_grid = {'svm__C': [0.1, 1.0, 10.0], 'svm__kernel': ['rbf', 'linear']}

grid = GridSearchCV(pipe, param_grid, cv=5, n_jobs=-1)
grid.fit(X_train, y_train)

best = grid.best_estimator_
print('Test accuracy:', best.score(X_test, y_test).round(4))

Scoring Options in GridSearchCV

By default GridSearchCV uses the estimator's default score (accuracy for classifiers). You can specify any metric with the scoring parameter: 'roc_auc', 'f1', 'neg_mean_squared_error', or a custom scorer made with make_scorer. For imbalanced datasets, 'f1_macro' or 'roc_auc' are better choices than raw accuracy.

from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer

X, y = load_breast_cancer(return_X_y=True)

pipe = Pipeline([('sc', StandardScaler()), ('lr', LogisticRegression(max_iter=300))])
param_grid = {'lr__C': [0.01, 0.1, 1.0, 10.0]}

grid = GridSearchCV(pipe, param_grid, cv=5, scoring='roc_auc', n_jobs=-1)
grid.fit(X, y)
print('Best C:', grid.best_params_)
print('Best ROC-AUC:', grid.best_score_.round(4))

Saving the Best Pipeline

After grid search, save the best pipeline to disk. This single file contains the scaler (with its fitted means and variances), the PCA (with its components), and the classifier (with its weights) — everything needed to reproduce predictions on new data. Load it in production and call predict directly.

import joblib

# Save the best estimator
joblib.dump(grid.best_estimator_, '/tmp/best_pipeline.pkl')

# Load and verify
loaded = joblib.load('/tmp/best_pipeline.pkl')
print('Loaded pipeline test score:', loaded.score(X_test, y_test).round(4))

Quick Check

Test your understanding of cross-validating and grid-searching a full pipeline from this lesson.

Lesson Recap

In this lesson you learned: cross_val_score on a Pipeline re-fits all steps per fold and gives honest generalisation estimates, double-underscore notation references nested hyperparameters in param_grid, and RandomizedSearchCV efficiently explores large parameter spaces by sampling a fixed number of random combinations. Next up we save and load a full pipeline with joblib for production deployment.

Gratis para empezar

Aprende Python con un tutor de IA — gratis

Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.

Cursos
30
Lecciones
120

Preguntas frecuentes

¿La lección «Validación cruzada y búsqueda en cuadrícula de un pipeline completo» es gratis?

Sí — el texto completo de «Validación cruzada y búsqueda en cuadrícula de un pipeline completo» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Machine Learning Academy, actualiza a CoddyKit PRO. El curso de Machine Learning Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Validación cruzada y búsqueda en cuadrícula de un pipeline completo»?

Pasará un Pipeline a cross_val_score y GridSearchCV, utilizando la notación de doble guion bajo para especificar los hiperparámetros de cada paso. Practicas Machine Learning Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Machine Learning Academy?

No se requiere experiencia previa. Machine Learning Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Validación cruzada y búsqueda en cuadrícula de un pipeline completo»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Machine Learning Academy?

Sí. Cada lección de Machine Learning Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Creación de su primer pipeline: escalador más clasificador
  2. ColumnTransformer dentro de un pipeline
  3. Validación cruzada y búsqueda en cuadrícula de un pipeline completo
  4. Guardado y carga de un pipeline con joblib
← Volver a Machine Learning Academy