In questo articolo vedremo come ottimizzare l’addestramento degli algoritmi di classificazione di Machine Learning, scegliendo adeguatamente il valore dei parametri configurabili all’interno di ogni algoritmo. Questa attività è nota come tuning degli iperparametri (o hyperparameter optimization). Il termine iperparametro è utilizzato per distinguere questa tipologia di parametri da quelli restituiti in output dall’algoritmo, come ad esempio i pesi di un algoritmo di regressione logistica. In questa lezione useremo il metodo GridSearchCV della libreria di Python scikit-learn, che implementa al suo interno anche la cross-validation vista nella lezione precedente.
Configurare una griglia di parametri in una pipeline
Procediamo come al solito a importare il dataset Iris, dividere i dati in training e test e creare una pipeline che contenga le operazioni basilari di pre-processing e l’algoritmo di regressione logistica.
from sklearn.pipeline import Pipeline
log_regression_pipeline =Pipeline([("vn", SimpleImputer(strategy="mean")),
("sc", StandardScaler()),
("lr", LogisticRegression(random_state=0 ))])
Questa volta però non procediamo subito con l’addestreremo del modello, ma applichiamo alla pipeline appena creata il metodo get_params().
log_regression_pipeline.get_params()
Otteniamo così l’elenco dei parametri configurabili per tutti gli step della pipeline, con il relativo valore attuale.

Vediamo ad esempio che il metodo SimpleImputer è configurato attualmente per utilizzare la media come strategia di sostituzione dei valori null. Potrei decidere di confrontare i risultati ottenuti utilizzando un valore differente, come la mediana.
Analogamente l’algoritmo di regressione logistica è configurato con il parametro C uguale a 1.0 (a differenza della media, non abbiamo specificato nel codice di creazione della pipeline il valore di C e quindi il valore indicato 1.0 è quello di default). Questo parametro è legato alla regolarizzazione del modello: modificare il suo valore può portare a importanti cambiamenti. Vogliamo dunque testare l’algoritmo con più valori distinti del parametro C, ad esempio 0.8, 0.85, 0.9, 0.95 e 1.
Creeremo allora una griglia con le varie combinazioni di parametri che vogliamo testare:
param_grid = [{"lr__C": [0.8, 0.85, 0.9, 0.95, 1],
"vn__strategy": ["median","mean"]}]
Facciamo attenzione a valorizzare le chiavi del dizionario così come indicato nell’output del metodo get_params().
GridSearchCV per il tuning degli iperparametri
A questo punto possiamo importare il metodo GridSearchCV e passargli in input:
- la pipeline che vogliamo ottimizzare
- la griglia dei parametri che vogliamo testare
- il numero di fold da utilizzare per eseguire la convalida incrociata e selezionare i valori migliori dei parametri
Ecco il codice:
from sklearn.model_selection import GridSearchCV
my_grid = GridSearchCV(estimator = my_first_pipeline,
param_grid = param_grid,
cv = 10 )
A questo punto lanciando il metodo fit eseguiremo ben 120 addestramenti! Più in particolare, per ognuna delle 10 combinazioni legate alla convalida incrociata, lanceremo l’algoritmo 12 volte relative a tutte le possibili combinazioni tra i due parametri lr__C e vn__strategy (6 per il primo e 2 per il secondo).
Facciamo attenzione quindi a valutare l’impatto computazionale dell’utilizzo della nostra griglia. In questo articolo stiamo analizzando il dataset Iris che contiene soltanto centocinquanta righe circa, quindi possiamo procedere tranquillamente e lanciare il metodo fit
my_grid.fit(x1,y1)
Jupyter-lab ci restituirà questa immagine di output

Creiamo il modello con gli iperparametri ottimizzati
Dopo aver eseguito l’addestramento, possiamo visualizzare la miglior combinazione trovata interrogando l’attributo best_params_
my_grid.best_params_

Tramite l’attributo best_score_ possiamo recuperare la media delle accuratezze ottenute con questo modello nelle 10 diverse suddivisioni eseguite dalla convalida incrociata. In questo caso il codice
my_grid.best_score_
restituirà 0.94. Possiamo dunque creare un nuovo modello utilizzando i migliori valori degli iperparametri appena ottenuti. Per far ciò possiamo sia creare manualmente la pipeline con quei parametri
best_lr_pipeline =Pipeline([("vn", SimpleImputer(strategy="median")),
("sc", StandardScaler()),
("lr", LogisticRegression(random_state=0, C=0.8))])
oppure recuperarla direttamente dall’attributo best_params_
best_lr_pipeline = my_grid.best_params_
La seconda opzione è sicuramente più veloce!
Valutiamo i risultati con il metodo score
Una volta ottenuto il modello migliore, posso valutarne l’accuratezza sul dataset di test, come spiegato nella lezione precedente.
best_lr_pipeline.fit(x1,y1)
best_lr_pipeline.score(x2,y2)
ottenendo in questo caso il 95%. Anche in questo caso sarei potuto arrivare allo stesso risultato un po’ più velocemente, utilizzando direttamente l’attributo score(). Infatti questa sequenza di operazioni:
- creare il modello con la scelta dei parametri migliori
- allenarlo sull’intero dataset di training
- valutarne l’accuratezza sui dati di test
è equivalente ad eseguire direttamente il codice
my_grid.score(x2,y2)
Continua a imparare
- Segui la lezione successiva sul clustering dei dati
- Torna all’indice delle lezioni
- Visita la pagina del mio corso online su Pandas, Python e Machine Learning