La Regressione Lineare con Elastic Net nel Machine Learning con scikit-learn

Elastic Net linear regression header

L’Elastic Net è una tecnica di regressione lineare che aggiunge un termine di regolarizzazione combinando sia la penalità L1 (come nella regressione Lasso) che la penalità L2 (come nella regressione ridge). Quindi, si basa sul modello di regressione lineare, ma con l’aggiunta di queste penalità per migliorare le prestazioni del modello, soprattutto quando ci sono multicollinearità tra le variabili o si desidera fare una selezione delle variabili.

Elastic Net

L’Elastic Net è stato introdotto nel 2005 da due ricercatori, Hui Zou e Trevor Hastie, nel loro articolo intitolato “Regularization and variable selection via the elastic net“, pubblicato sulla rivista “Journal of the Royal Statistical Society: Series B (Statistical Methodology)”.

Zou e Hastie hanno sviluppato l’Elastic Net come una soluzione per affrontare le limitazioni della regressione Lasso e della regressione ridge, due tecniche di regressione ampiamente utilizzate. Entrambe queste tecniche avevano i loro vantaggi, ma anche dei drawback significativi: la regressione Lasso tendeva a selezionare un sottoinsieme ridotto di variabili predittive, mentre la regressione ridge manteneva tutte le variabili ma non eseguiva una vera selezione variabile.

L’Elastic Net ha combinato le caratteristiche di entrambi i metodi, introducendo una regolarizzazione mista che include sia la penalità L1 che la penalità L2. Questo ha permesso di ottenere i benefici della selezione variabile della regressione Lasso e la stabilità della regressione ridge.

L’articolo di Zou e Hastie ha suscitato un grande interesse nella comunità statistica e machine learning, portando all’adozione diffusa dell’Elastic Net in varie aree di applicazione. Da allora, l’Elastic Net è diventato uno strumento molto popolare per la regressione e l’analisi dei dati, utilizzato per affrontare una vasta gamma di problemi, inclusi quelli con dati ad alta dimensionalità e multicollinearità.

L’Elastic Net è un modello di regressione che combina gli aspetti della regressione lineare e della regressione Lasso (Least Absolute Shrinkage and Selection Operator) per gestire problemi di multicollinearità e selezione delle variabili.

La regressione lineare tradizionale può soffrire di problemi di multicollinearità quando le variabili indipendenti sono fortemente correlate tra loro. La regressione Lasso affronta questo problema imponendo una penalità sulla somma dei valori assoluti dei coefficienti durante il processo di addestramento, che tende a ridurre alcuni coefficienti a zero, eseguendo così una sorta di selezione delle variabili.

Tuttavia, la regressione Lasso può essere troppo rigida nella selezione delle variabili, eliminando troppi coefficienti e potenzialmente ignorando variabili utili.

L’Elastic Net si propone di superare queste limitazioni combinando la penalità della regressione Lasso con una penalità aggiuntiva, simile alla norma L2 della regressione ridge. Questo consente all’Elastic Net di mantenere alcuni dei vantaggi della regressione Lasso nella selezione delle variabili, mentre allo stesso tempo allevia la tendenza eccessiva alla selezione delle variabili quando ci sono forti correlazioni tra i predittori.

La forma generale della funzione obiettivo per l’Elastic Net è:

 \text{minimize} \left( \frac{1}{2n} ||\mathbf{y} - \mathbf{X}\beta||_2^2 + \lambda_1 ||\beta||_1 + \lambda_2 ||\beta||_2^2 \right)

Dove:

  • \mathbf{y} è il vettore delle risposte;
  • \mathbf{X} è la matrice delle caratteristiche;
  • \beta è il vettore dei coefficienti dei predittori;
  • ||\cdot||_1 è la norma L1;
  • ||\cdot||_2 è la norma L2;
  • \lambda_1 e \lambda_2 sono i parametri di regolarizzazione.

In sintesi, l’Elastic Net offre una flessibilità maggiore rispetto alla regressione Lasso e alla regressione ridge, permettendo di gestire efficacemente problemi di multicollinearità e selezione delle variabili.

Elastic Net con scikit-learn per la Regressione Lineare

Elastic Net è integrato nella libreria scikit-learn di Python. che è una delle librerie più utilizzate per il machine learning. In scikit-learn, puoi utilizzare la classe ElasticNet per addestrare modelli di regressione Elastic Net.

In questo esempio, utilizzeremo un modello di regressione Elastic Net che si addestrerà su dati sintetici generati casualmente utilizzando make_regression da scikit-learn. Una volta generato un dataset, questo verrà suddiviso in due porzioni: training set e testing set. Useremo la funzione fit per addestrare il modello sul set di addestramento. Una volta addestrato, effettueremo delle previsioni sul testing set utilizzando predict. Per valutare le prestazioni del modello si usa come metrica l’errore quadratico medio. Questo valore è facilmente ricavabile dalla funzione mean_squared_error fornita da scikit-learn. Ecco il codice che svolge tutte queste mansioni:

from sklearn.linear_model import ElasticNet
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# Generate synthetic data for the example
X, y = make_regression(n_samples=100, n_features=10, noise=0.1, random_state=42)

# Split the dataset into training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Define the Elastic Net model
elastic_net = ElasticNet(alpha=0.1, l1_ratio=0.5, random_state=42)

# Train the model on the training data
elastic_net.fit(X_train, y_train)

# Make predictions on the test set
predictions = elastic_net.predict(X_test)

# Evaluate the model's performance
mse = mean_squared_error(y_test, predictions)
print("Mean Squared Error:", mse)

Eseguendo si ottiene il valore MSE:

Mean Squared Error: 176.0283275056508

Essendo questo un valore che, sì che deve essere il più piccolo possibile, ma letto in valore assoluto non ci dà alcuna informazione. Possiamo utilizzare un rappresentazione grafica molto utile che ci permette di intuire di come i valori previsti si discostino da quelli reali per tutto il range del dataset. Ecco il codice per generare il grafico:

import matplotlib.pyplot as plt

# Plot of predictions versus actual values
plt.scatter(y_test, predictions)
plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], 'r--')
plt.xlabel("Actual Values")
plt.ylabel("Predictions")
plt.title("Scatter plot: Actual Values vs Predictions")
plt.show()

Eseguendo si ottiene il grafico descritto in precedenza.

Elastic Net linear regression - scatter plot dataset

Come possiamo vedere i punti non si discostano molto dalla diagonale rossa ( valore previsto = valore reale). Quindi il nostro modello si è dimostrato in questo caso un buon modello di previsione.

Una metrica che ci fornisce delle informazioni simili è R^2 (o coefficiente di determinazione). Questa è una metrica comune utilizzata per valutare la bontà di previsione dei modelli di regressione. R^2 misura la proporzione di varianza della variabile dipendente che viene spiegata dal modello. Un valore più vicino a 1 indica un modello migliore, mentre un valore più vicino a 0 indica un modello peggiore.

from sklearn.metrics import r2_score

r2 = r2_score(y_test, predictions)
print("Coefficient R^2:", r2)

Eseguendo si ottiene il valore della metrica:

Coefficient R^2: 0.9970546671780763

Come possiamo vedere è un valore molto prossimo a 1. Questo non fa che confermare quanto detto dopo la visualizzazione del grafico precedente.

Esempio con il dataset diabetes per una Regressione Lineare con Elastic Net

Finora il modello si è comportato egregiamente nel prevedere dei valori generati artificialmente. Ma come si comporterà con un dataset di dati reali, come per esempio diabetes fornito dalla libreria scikit-net.

Il dataset “diabetes” incluso nella libreria scikit-learn è un dataset di esempio che contiene misurazioni derivate da pazienti diabetici. È comunemente usato per scopi di apprendimento automatico e di analisi dei dati.

Ecco una rapida descrizione delle caratteristiche del dataset “diabetes”:

  • Numero di campioni: 442
  • Numero di attributi/predittori: 10
  • Tipo di attributi/predittori: Numerici (float)
  • Variabile di risposta/target: Valori quantitativi misurati, che rappresentano la progressione della malattia del diabete in un anno.

I 10 attributi/predittori rappresentano:

  1. Age: Età dei pazienti.
  2. Sex: Genere dei pazienti (0 per maschio, 1 per femmina).
  3. Body mass index (BMI): Indice di massa corporea.
  4. Average blood pressure (BP): Pressione sanguigna media.
  5. S1, S2, S3, S4, S5, S6: Sei misure sierologiche derivate da un siero di sangue.

Il target rappresenta la progressione della malattia del diabete in un anno e viene rappresentato come una misura quantitativa della progressione della malattia.

Questo dataset viene spesso utilizzato per esempi didattici e per valutare le prestazioni di algoritmi di regressione nell’ambito del machine learning. Vediamo come si comporta il nostro modello Elastic Net al riguardo.

from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.linear_model import ElasticNet
from sklearn.metrics import mean_squared_error, r2_score

# Load the "diabetes" dataset
diabetes = load_diabetes()
X = diabetes.data
y = diabetes.target

# Split the dataset into training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Define the Elastic Net model
elastic_net = ElasticNet(alpha=0.1, l1_ratio=0.5, random_state=42)

# Train the model on the training data
elastic_net.fit(X_train, y_train)

# Make predictions on the test set
predictions = elastic_net.predict(X_test)

# Calculate the Mean Squared Error (MSE) and the coefficient R^2
mse = mean_squared_error(y_test, predictions)
r2 = r2_score(y_test, predictions)

print("Mean Squared Error (MSE):", mse)
print("Coefficient R^2:", r2)

Eseguendo si ottengono i valori:

Mean Squared Error (MSE): 4775.466767154695
Coefficient R^2: 0.09865421116113748

Non si tratta certo di ottimi risultati…

Migliorare il modello: la ricerca dei parametri ottimali

Si potrebbe pensare di adottare una strategia di ricerca dei parametri ottimali utilizzando la ricerca casuale per esplorare diverse combinazioni di iperparametri per il modello Elastic Net. Ecco un esempio di come potremmo farlo utilizzando la classe RandomizedSearchCV di scikit-learn:

from sklearn.model_selection import RandomizedSearchCV
import numpy as np

# Define the parameter grid to explore
param_grid = {
    'alpha': np.linspace(0.1, 1.0, 10),  # alpha values from 0.1 to 1.0
    'l1_ratio': np.linspace(0.1, 0.9, 9)  # l1_ratio values from 0.1 to 0.9
}

# Initialize the Elastic Net model
elastic_net = ElasticNet(random_state=42)

# Search for optimal parameters using random search
random_search = RandomizedSearchCV(estimator=elastic_net, param_distributions=param_grid, n_iter=100, cv=5, scoring='neg_mean_squared_error', random_state=42)
random_search.fit(X_train, y_train)

# Get the best model
best_elastic_net = random_search.best_estimator_

# Make predictions on the test set
predictions = best_elastic_net.predict(X_test)

# Calculate Mean Squared Error (MSE) and Coefficient R^2
mse = mean_squared_error(y_test, predictions)
r2 = r2_score(y_test, predictions)

print("Mean Squared Error (MSE):", mse)
print("Coefficient R^2:", r2)
print("Best parameters:", random_search.best_params_)

In questo codice, definiamo una griglia di parametri da esplorare per alpha e l1_ratio, e utilizziamo RandomizedSearchCV per eseguire una ricerca casuale su questa griglia. Dopo aver trovato i parametri ottimali, addestriamo un nuovo modello Elastic Net utilizzando questi parametri ottimali e valutiamo le prestazioni del modello sul set di test. Infine, stampiamo il MSE, R^2 e i migliori parametri trovati.

Mean Squared Error (MSE): 3792.129166396345
Coefficient R^2: 0.2842543312471031
Best parameters: {'l1_ratio': 0.9, 'alpha': 0.1}

Siamo ancora ben lontani…

Migliorare il modello: la normalizzazione dei dati

I risultati ottenuti, sebbene migliorati rispetto alla precedente iterazione, non sono ancora soddisfacenti. Tuttavia, possiamo continuare ad esplorare ulteriori strategie per cercare di migliorare le prestazioni del modello.

Certamente! La normalizzazione dei dati è una pratica comune nel machine learning che può contribuire a migliorare le prestazioni del modello, specialmente quando le caratteristiche dei dati hanno scale diverse. Possiamo utilizzare la standardizzazione o la normalizzazione min-max per normalizzare i dati.

Ecco un esempio di come possiamo applicare la standardizzazione dei dati utilizzando StandardScaler di scikit-learn e poi addestrare nuovamente il modello Elastic Net:

from sklearn.preprocessing import StandardScaler

# Data standardization
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# Training the Elastic Net model on standardized data
elastic_net = ElasticNet(alpha=0.1, l1_ratio=0.9, random_state=42)
elastic_net.fit(X_train_scaled, y_train)

# Predictions on the test set
predictions = elastic_net.predict(X_test_scaled)

# Calculating MSE and R^2
mse = mean_squared_error(y_test, predictions)
r2 = r2_score(y_test, predictions)

print("Mean Squared Error (MSE) with normalization:", mse)
print("Coefficient R^2 with normalization:", r2)

In questo codice, applichiamo la standardizzazione dei dati utilizzando StandardScaler sui dati di addestramento e di test. Successivamente, addestriamo il modello Elastic Net sui dati standardizzati e calcoliamo il MSE e il coefficiente R^2 utilizzando le previsioni del modello.

Mean Squared Error (MSE) with normalization:: 2878.8291644017645
Coefficient R^2 with normalization:: 0.45663520015111103

Abbiamo raddoppiato la capacità previsionale del modello, ma comunque un valore di 0.45 di R^2 è ancora troppo basso. La normalizzazione dei dati può aiutare il modello a convergere più rapidamente e può migliorare le prestazioni in generale. Tuttavia, è importante testare l’effetto della normalizzazione dei dati sulle prestazioni del modello e valutare se migliorano effettivamente le prestazioni.

Migliorare il Modello: L’ingegneria delle Feature

L’ingegneria delle feature è un passo importante nel processo di sviluppo di un modello di machine learning. Possiamo esplorare diverse trasformazioni delle feature esistenti o creare nuove feature basate su quelle esistenti per cercare di catturare meglio le relazioni tra le variabili indipendenti e dipendenti.

Ecco alcuni esempi di possibili tecniche di ingegneria delle feature che potremmo considerare per il dataset “diabetes”:

  • Polynomial Features: Possiamo creare nuove feature come polinomi delle feature esistenti, ad esempio aggiungendo feature quadratiche o cubiche per catturare relazioni non lineari.
  • Interazioni tra feature: Possiamo creare nuove feature come interazioni tra le feature esistenti, ad esempio moltiplicando due feature tra loro.
  • Trasformazioni delle feature: Possiamo applicare trasformazioni alle feature esistenti, ad esempio logaritmiche o quadratiche, per catturare relazioni non lineari o per migliorare la distribuzione dei dati.
  • Riduzione delle dimensioni: Possiamo esplorare tecniche di riduzione delle dimensioni come PCA (Principal Component Analysis) per ridurre la dimensionalità del dataset mantenendo la maggior parte delle informazioni.
  • Encoding delle variabili categoriche: Se il dataset contiene variabili categoriche, possiamo esplorare diverse tecniche di encoding, ad esempio one-hot encoding o label encoding, per rappresentare queste variabili in modo appropriato.
  • Aggiunta di informazioni esterne: Se disponibile, possiamo aggiungere informazioni esterne al dataset che potrebbero essere rilevanti per il problema, ad esempio dati demografici o informazioni sui pazienti.

Tra le opzioni possibili proviamo a ridurre le dimensioni, usando la tecnica PCA ed applicare le polynomial feature . Per farlo, definiamo un pipeline che combina la normalizzazione dei dati con PCA. Successivamente, applichiamo il pipeline ai dati di addestramento e di test e quindi aggiungiamo le feature polinomiali di grado 2.

from sklearn.decomposition import PCA
from sklearn.pipeline import Pipeline

# Definition of the pipeline with normalization and PCA
pipeline = Pipeline([
    ("scaler", StandardScaler()),
    ("pca", PCA(n_components=0.95))  # Preserve 95% of variance
])

# Application of the pipeline to training and test data
X_train_pca = pipeline.fit_transform(X_train)
X_test_pca = pipeline.transform(X_test)

# Adding polynomial features of degree 2
poly = PolynomialFeatures(degree=2)
X_train_poly = poly.fit_transform(X_train_pca)
X_test_poly = poly.transform(X_test_pca)

# Training the Elastic Net model on polynomial features
elastic_net = ElasticNet(alpha=0.1, l1_ratio=0.9, random_state=42)
elastic_net.fit(X_train_poly, y_train)

# Predictions on the test set
predictions = elastic_net.predict(X_test_poly)

# Calculating MSE and R^2
mse = mean_squared_error(y_test, predictions)
r2 = r2_score(y_test, predictions)

print("Mean Squared Error (MSE) with PCA and polynomial features:", mse)
print("Coefficient R^2 with PCA and polynomial features:", r2)

Mean Squared Error (MSE) with PCA and polynomial features: 2605.224776619983
Coefficient R^2 with PCA and polynomial features: 0.5082766783059008

È un ulteriore miglioramento delle prestazioni del modello! La combinazione di normalizzazione dei dati con PCA e feature polinomiali ha portato a una riduzione ulteriore dell’errore quadratico medio (MSE) e un aumento del coefficiente R^2, indicando che il modello sta fornendo previsioni migliori.

E così via. Comunque in questi casi, si dovrebbe valutare la possibilità di utilizzare metodi diversi e vedere se si ottengono risultati migliori, prima di continuare a procedere con processi di ottimizzazione sempre più complessi (dato che siamo ancora intorno a R^2 = 0.5 ).

Quando usare Elastic Net nelle Regressioni Lineari

L’esempio precedente ci fa comprendere che la scelta del modello giusto può fare la differenza nelle capacità previsionali, soprattutto nell’ambito di ciascun dataset. Vediamo un po’ di regole che ci potrebbero essere utili al riguardo.

La scelta tra Elastic Net e altri metodi di regressione lineare dipende dalle caratteristiche specifiche del problema e dei dati. Ecco alcune considerazioni su quando potrebbe essere opportuno scegliere Elastic Net rispetto ad altri metodi di regressione lineare:

  1. Gestione della multicollinearità: Se il dataset contiene variabili fortemente correlate tra loro, Elastic Net può essere preferibile rispetto alla regressione lineare standard (OLS) poiché combina la regolarizzazione L1 e L2 per affrontare meglio il problema della multicollinearità.
  2. Selezione delle variabili: Se il tuo obiettivo è selezionare un sottoinsieme di variabili predittive, Lasso potrebbe essere preferibile poiché tende a ridurre alcuni coefficienti a zero, eseguendo quindi una selezione variabile automatica. Tuttavia, se vuoi una selezione delle variabili più stabile e meno soggetta a errori di campionamento, Elastic Net potrebbe essere preferibile.
  3. Predizioni stabili: Se il tuo obiettivo principale è ottenere predizioni stabili, Ridge può essere preferibile poiché riduce la varianza del modello mantenendo tutte le variabili. Tuttavia, se hai un problema di regressione in cui alcune variabili sono ritenute poco rilevanti e potrebbero essere escluse, Elastic Net potrebbe essere una scelta migliore rispetto a Ridge.
  4. Equilibrio tra bias e varianza: Elastic Net cerca di trovare un equilibrio tra bias (errore sistemico) e varianza (sensibilità ai dati di addestramento). Se hai bisogno di un modello con un buon compromesso tra queste due fonti di errore, Elastic Net può essere una scelta appropriata rispetto ad altri metodi.
  5. Robustezza alle violazioni delle assunzioni della regressione lineare: Elastic Net è relativamente robusto alle violazioni delle assunzioni della regressione lineare, come la normalità dei residui e l’omoscedasticità degli errori, rispetto alla regressione lineare standard.

Elastic Net è un metodo di regolarizzazione che combina sia la regolarizzazione L1 (lasso) che la regolarizzazione L2 (ridge). È particolarmente utile quando ci sono molte variabili predittive nel dataset o quando queste variabili sono fortemente correlate tra loro (multicollinearità).

Tuttavia, non esiste un metodo di regressione che sia universalmente ottimale per tutti i tipi di dataset. Ci sono diversi motivi per cui Elastic Net potrebbe non funzionare bene con un dataset specifico come “diabetes”:

  1. Dimensione del dataset: Elastic Net tende a funzionare meglio quando ci sono molte variabili predittive rispetto al numero di osservazioni nel dataset. Se il dataset ha un numero limitato di osservazioni rispetto al numero di variabili, i metodi di regolarizzazione come Elastic Net potrebbero non essere in grado di catturare adeguatamente la struttura dei dati.
  2. Relazioni non lineari complesse: Elastic Net è un modello lineare e potrebbe non essere in grado di catturare relazioni non lineari complesse presenti nei dati. In tal caso, potrebbe essere necessario utilizzare modelli più complessi come reti neurali o modelli basati su alberi decisionali.
  3. Poca correlazione tra le variabili predittive: Se le variabili predittive nel dataset non sono fortemente correlate tra loro, l’aggiunta della regolarizzazione L1 di Elastic Net potrebbe non portare a una significativa riduzione dei coefficienti. In questo caso, potrebbe essere preferibile utilizzare la regolarizzazione L2 di Ridge, che tende a funzionare meglio quando le variabili sono poco correlate.
  4. Caratteristiche non normalizzate: Elastic Net e altri metodi di regressione regolarizzata possono essere sensibili alla scala delle caratteristiche. Se le caratteristiche non sono normalizzate o standardizzate correttamente, ciò potrebbe influenzare negativamente le prestazioni del modello.

In sintesi, se Elastic Net non funziona bene con un determinato dataset come “diabetes”, potrebbe essere necessario esplorare altre opzioni, come l’ottimizzazione degli iperparametri, l’ingegneria delle feature o l’uso di modelli più complessi, per ottenere prestazioni migliori.

Lascia un commento