Régression de signaux creux avec des modèles basés sur L1

Machine LearningMachine LearningBeginner
Pratiquer maintenant

This tutorial is from open-source community. Access the source code

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Dans ce laboratoire, nous allons démontrer comment utiliser des modèles de régression basés sur L1 pour traiter des signaux à haute dimension et creux. En particulier, nous comparerons trois modèles populaires basés sur L1 : Lasso, Automatic Relevance Determination (ARD) et ElasticNet. Nous utiliserons un ensemble de données synthétiques pour illustrer les performances de ces modèles en termes de temps d'ajustement, de score R2 et de rareté des coefficients estimés.

Conseils sur la machine virtuelle

Une fois le démarrage de la machine virtuelle terminé, cliquez dans le coin supérieur gauche pour basculer vers l'onglet Notebook pour accéder à Jupyter Notebook pour la pratique.

Parfois, vous devrez peut-être attendre quelques secondes pour que Jupyter Notebook ait fini de charger. La validation des opérations ne peut pas être automatisée en raison des limitations de Jupyter Notebook.

Si vous rencontrez des problèmes pendant l'apprentissage, n'hésitez pas à demander à Labby. Donnez des commentaires après la session, et nous réglerons rapidement le problème pour vous.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL sklearn(("Sklearn")) -.-> sklearn/ModelSelectionandEvaluationGroup(["Model Selection and Evaluation"]) ml(("Machine Learning")) -.-> ml/FrameworkandSoftwareGroup(["Framework and Software"]) sklearn(("Sklearn")) -.-> sklearn/CoreModelsandAlgorithmsGroup(["Core Models and Algorithms"]) sklearn/CoreModelsandAlgorithmsGroup -.-> sklearn/linear_model("Linear Models") sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/model_selection("Model Selection") sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/metrics("Metrics") ml/FrameworkandSoftwareGroup -.-> ml/sklearn("scikit-learn") subgraph Lab Skills sklearn/linear_model -.-> lab-49187{{"Régression de signaux creux avec des modèles basés sur L1"}} sklearn/model_selection -.-> lab-49187{{"Régression de signaux creux avec des modèles basés sur L1"}} sklearn/metrics -.-> lab-49187{{"Régression de signaux creux avec des modèles basés sur L1"}} ml/sklearn -.-> lab-49187{{"Régression de signaux creux avec des modèles basés sur L1"}} end

Générer un ensemble de données synthétiques

Tout d'abord, nous générons un ensemble de données où le nombre d'échantillons est inférieur au nombre total de caractéristiques. Cela conduit à un système sous-déterminé, c'est-à-dire que la solution n'est pas unique et que nous ne pouvons pas appliquer une méthode des moindres carrés ordinaires par elle-même. La régularisation introduit un terme de pénalité dans la fonction objectif, ce qui modifie le problème d'optimisation et peut aider à atténuer la nature sous-déterminée du système. Nous allons générer une variable cible y qui est une combinaison linéaire de signaux sinusoidaux avec des signes alternés. Seulement les 10 fréquences les plus basses sur les 100 fréquences de X sont utilisées pour générer y, tandis que les autres caractéristiques ne sont pas informatives. Cela résulte en un espace de caractéristiques creux à haute dimension, où un certain degré de pénalisation L1 est nécessaire.

import numpy as np

rng = np.random.RandomState(0)
n_samples, n_features, n_informative = 50, 100, 10
time_step = np.linspace(-2, 2, n_samples)
freqs = 2 * np.pi * np.sort(rng.rand(n_features)) / 0.01
X = np.zeros((n_samples, n_features))

for i in range(n_features):
    X[:, i] = np.sin(freqs[i] * time_step)

idx = np.arange(n_features)
true_coef = (-1) ** idx * np.exp(-idx / 10)
true_coef[n_informative:] = 0  ## sparsify coef
y = np.dot(X, true_coef)

## introduce random phase using numpy.random.random_sample
## add some gaussian noise using numpy.random.normal
for i in range(n_features):
    X[:, i] = np.sin(freqs[i] * time_step + 2 * (rng.random_sample() - 0.5))
    X[:, i] += 0.2 * rng.normal(0, 1, n_samples)

y += 0.2 * rng.normal(0, 1, n_samples)

## split the data into train and test sets using train_test_split from sklearn
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, shuffle=False)

Lasso

Dans cette étape, nous allons démontrer comment utiliser le modèle de régression Lasso pour estimer les coefficients creux de l'ensemble de données. Nous utiliserons une valeur fixe du paramètre de régularisation alpha. En pratique, le paramètre optimal alpha devrait être sélectionné en passant une stratégie de validation croisée TimeSeriesSplit à un LassoCV. Pour garder l'exemple simple et rapide à exécuter, nous définissons directement la valeur optimale pour alpha ici.

from sklearn.linear_model import Lasso
from sklearn.metrics import r2_score
from time import time

t0 = time()
lasso = Lasso(alpha=0.14).fit(X_train, y_train)
print(f"Lasso fit done in {(time() - t0):.3f}s")

y_pred_lasso = lasso.predict(X_test)
r2_score_lasso = r2_score(y_test, y_pred_lasso)
print(f"Lasso r^2 on test data : {r2_score_lasso:.3f}")

Automatic Relevance Determination (ARD)

Une régression ARD est la version bayésienne du Lasso. Elle peut produire des estimations d'intervalle pour tous les paramètres, y compris la variance d'erreur, si nécessaire. C'est une option appropriée lorsque les signaux ont un bruit gaussien.

from sklearn.linear_model import ARDRegression

t0 = time()
ard = ARDRegression().fit(X_train, y_train)
print(f"ARD fit done in {(time() - t0):.3f}s")

y_pred_ard = ard.predict(X_test)
r2_score_ard = r2_score(y_test, y_pred_ard)
print(f"ARD r^2 on test data : {r2_score_ard:.3f}")

ElasticNet

ElasticNet est un compromis entre la régression Lasso et la régression Ridge, car elle combine une pénalité L1 et une pénalité L2. Le degré de régularisation est contrôlé par les deux hyperparamètres l1_ratio et alpha. Pour l1_ratio = 0, la pénalité est purement L2 et le modèle est équivalent à une régression Ridge. De même, l1_ratio = 1 est une pénalité pure L1 et le modèle est équivalent à une régression Lasso. Pour 0 < l1_ratio < 1, la pénalité est une combinaison de L1 et L2.

from sklearn.linear_model import ElasticNet

t0 = time()
enet = ElasticNet(alpha=0.08, l1_ratio=0.5).fit(X_train, y_train)
print(f"ElasticNet fit done in {(time() - t0):.3f}s")

y_pred_enet = enet.predict(X_test)
r2_score_enet = r2_score(y_test, y_pred_enet)
print(f"ElasticNet r^2 on test data : {r2_score_enet:.3f}")

Représentation graphique et analyse des résultats

Dans cette étape, nous utilisons une heatmap pour visualiser la rareté des coefficients réels et estimés des modèles linéaires respectifs.

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from matplotlib.colors import SymLogNorm

df = pd.DataFrame(
    {
        "Vraies coefficients": true_coef,
        "Lasso": lasso.coef_,
        "ARDRegression": ard.coef_,
        "ElasticNet": enet.coef_,
    }
)

plt.figure(figsize=(10, 6))
ax = sns.heatmap(
    df.T,
    norm=SymLogNorm(linthresh=10e-4, vmin=-1, vmax=1),
    cbar_kws={"label": "Valeurs des coefficients"},
    cmap="seismic_r",
)
plt.ylabel("Modèle linéaire")
plt.xlabel("Coefficients")
plt.title(
    f"Coefficients des modèles\nLasso $R^2$: {r2_score_lasso:.3f}, "
    f"ARD $R^2$: {r2_score_ard:.3f}, "
    f"ElasticNet $R^2$: {r2_score_enet:.3f}"
)
plt.tight_layout()

Sommaire

On sait que le Lasso permet de récupérer efficacement des données creuses, mais ne fonctionne pas bien avec des caractéristiques fortement corrélées. En effet, si plusieurs caractéristiques corrélées contribuent à la variable cible, le Lasso finira par n'en sélectionner qu'une seule. Dans le cas de caractéristiques creuses mais non corrélées, un modèle Lasso serait plus approprié.

ElasticNet introduit une certaine rareté dans les coefficients et les réduit à zéro. Ainsi, en présence de caractéristiques corrélées qui contribuent à la variable cible, le modèle est toujours capable de réduire leurs poids sans les ramener exactement à zéro. Cela conduit à un modèle moins creux qu'un Lasso pur et peut également capturer des caractéristiques non prédictives.

ARDRegression est meilleur lorsqu'il s'agit de gérer un bruit gaussien, mais est toujours incapable de gérer des caractéristiques corrélées et nécessite un temps plus important en raison de l'ajustement d'une a priori.