Machine Learning Academy · Lezione

Cross-validation e grid search di una pipeline completa

Imparerete a passare una Pipeline a cross_val_score e GridSearchCV, usando la notazione con doppio underscore per specificare gli iperparametri dei singoli passaggi.

Lezione 3 di 413 passaggi

Cross-validation e grid search di una pipeline completa è una lezione Machine Learning Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Machine Learning Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Machine Learning Academy include 4 lezioni in totale.

Parti di questa lezione non sono ancora state tradotte e vengono mostrate in inglese.

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 per iniziare

Impara Python con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
30
Lezioni
120

Domande Frequenti

La lezione «Cross-validation e grid search di una pipeline completa» è gratuita?

Sì — il testo completo di «Cross-validation e grid search di una pipeline completa» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Machine Learning Academy, passa a CoddyKit PRO. Il corso Machine Learning Academy include 4 lezioni in totale.

Cosa imparerò in «Cross-validation e grid search di una pipeline completa»?

Imparerete a passare una Pipeline a cross_val_score e GridSearchCV, usando la notazione con doppio underscore per specificare gli iperparametri dei singoli passaggi. Eserciti Machine Learning Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Machine Learning Academy?

Non è richiesta alcuna esperienza precedente. Machine Learning Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Cross-validation e grid search di una pipeline completa»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Machine Learning Academy?

Sì. Ogni lezione Machine Learning Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Costruire la prima pipeline: scaler più classificatore
  2. ColumnTransformer all’interno di una pipeline
  3. Cross-validation e grid search di una pipeline completa
  4. Salvare e caricare una pipeline con joblib
← Torna a Machine Learning Academy