• 10 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 23/04/2024

Découvrez le principe de la régression linéaire

Découvrez le principe de la régression linéaire

La régression linéaire est le modèle le plus simple pour modéliser et prédire des valeurs continues en fonction d'autres variables.

Pensez-y comme une ligne droite qui relie les points dans un nuage de données, captant ainsi la tendance générale des observations.

Des points sont placés sur un graphique en abscisse et ordonnées. On peut tracer une ligne droite qui relie les points. Cette ligne permet de capter une tendance générale.

De façon plus rigoureuse, lorsque l'on prédit une variable cible    $\(y\)$   à partir d'une variable de prédiction   $\(x\)$    , la régression linéaire consiste à trouver les coefficients    $\(a\)$   et    $\(b\)$   dans l'équation de la droite qui va être la plus proche de tous les points du nuage de points :

 $\(y = a x + b\)$

Dans le cas de 2 variables de prédiction    $\(x_1\)$   et    $\(x_2\)$   de   $\(y\)$   , le modèle correspond à l'équation du plan défini par :

 $\(y = a_1 x_1 + a_2 x_2 + b\)$

De façon générale, si on a    $\(N\)$   variables   $\( x_1 , ..., x_N\)$   de prédictions dans notre jeu de données pour la prédiction d'une variable cible    $\(y\)$ , le modèle de regression linéaire consiste à trouver les    $\(N\)$   coefficients    $\(a_1 , ..., a_N\)$   de l'équation :

 $\(y = a_1 x_1 +_ a_2 x_2 + ... + a_N x_N + b\)$

De façon abrégée nous écrirons :

 $\(y\)$$\(x_1 + x_2 + + x_N\)$

Notez le signe  ~  qui veut dire que l'on régresse la variable cible    $\(y\)$   par rapport aux variables de prédictions    $\(x_1, ..., x_N\)$   .

La simplicité de la régression linéaire lui confère des propriétés précieuses :

  • interprétabilité : le poids respectif des coefficients correspond au poids relatif des prédicteurs ;

  • facilité d'implémentation : il existe beaucoup de langages et de librairies ;

  • rapidité de calcul : optimisés depuis longtemps, les calculs sont hyper rapides ;

  • légère en mémoire : donc adaptée à l'Internet des Objets (IoT) basé sur des senseurs de faible puissance.  

Comprenez les limites de la régression linéaire

Utiliser une régression linéaire nécessite cependant de prendre quelques précautions.

Limite n° 1 : Utiliser une régression linéaire à partir d’un cas non linéaire ne marchera pas

Il faut s'assurer que la relation entre la variable cible et les prédicteurs soit linéaire. Utiliser une régression linéaire dans des cas évidemment non linéaires ne marchera pas.

Mais qu'est-ce qu'un cas non linéaire ?

Supposons que nous ayons une relation quadratique entre la variable cible et un prédicteur $\(y = a*x^2\)$ + du bruit comme sur le graphe ci-dessous. On voit bien que la droite de la régression linéaire n'explique en rien la relation entre le prédicteur et la cible.

L'image montre un nuage de points dans le cas d'une relation quadratique entre les variables illustrant le cas où la régression linéaire (simple droite) n'est pas appropriée.

Limite n° 2 : des variations d'amplitude significative peuvent fausser l'importance des coefficients

Une autre précaution utile concerne l'amplitude respective des variables.

Les valeurs des coefficients de la régression linéaire sont en effet inversement proportionnelles à l'amplitude de la variable associée.

Si une variable est 1 000 fois plus grande en moyenne qu'une autre variable, et si ces 2 variables ont le même pouvoir de prédiction sur la variable cible, alors le coefficient de la grande variable sera 1 000 fois plus petit que celui de la deuxième variable.

En normalisant les variables afin que leur amplitude soit comprise dans un intervalle comparable, chaque coefficient de la régression linéaire reflète directement l'impact de la variable sur la variable cible, son pouvoir de prédiction.

À nous de jouer : Let's regress!

C'est un dataset classique issu du livre référence An introduction to Statistical Learning. Il contient 200 échantillons sur le budget alloué aux publicités télévisées, à la radio et dans les journaux, ainsi que les ventes résultantes.

  • Variable cible :  ventes  (  sales  dans la version originale).

  • Prédicteurs : budgets de publicité :

    • pour la TV :  tv  ;

    • pour la la radio :  radio  ;

    • pour la presse :  journaux  (  newspaper  dans la version originale).

La variable cible,  ventes  , est continue, donc nous sommes bien dans une logique de régression (et non de classification).

Nous allons essayer de prédire le volume de vente en fonction du budget publicitaire en TV, radio et journaux.

Chargeons et explorons le dataset.

import pandas as pd
df = pd.read_csv(<url du dataset>;)
# Explorons rapidement les données avec
df.head()
df.describe()

La fonction  regplot()  permet non seulement d'afficher le nuage de points des variables  tv  ,  radio  et  journaux  en fonction des ventes, mais aussi de tracer la ligne de régression.

Courbes montrant la relation entre les ventes et 3 media : télévision, radio, journaux. Pour le premier, le nuage de points est assez proche de la ligne. Pour la radio, le nuage de point est dispersé. Il l'est encore plus pour les journaux.

La zone bleu pâle reflète l'incertitude du modèle. Plus elle est grande, moins la régression est fiable.

Le graphe montre que :

  • tv  est plus prédictive des ventes que  radio  ;

  • radio  est plus prédictive que  journaux  .

L'observation est confirmée par les coefficients de corrélation :

df.corr()
- tv     0.78
- radio    0.58
- journaux  0.23

Choisissons le modèle de régression linéaire de scikit-learn.

from sklearn.linear_model import LinearRegression
reg = LinearRegression()

Cette fonction prends les variables d'entrée, la variable cible, un ratio et retourne 4 objets :

  • X_train  : prédicteurs pour l'entraînement ;

  • X_test  : prédicteurs pour l'évaluation ;

  • y_train  : variable cible pour l'entraînement ;

  • y_test  : variable pour l'évaluation.

On va ensuite utiliser :

  • X_train  et  y_train  pour entraîner le modèle (train en anglais) ;

  • X_test  et  y_test  pour l'évaluer (test en anglais).

Cela donne :

from sklearn.model_selection import train_test_split
X = df[['tv','radio','journaux']]
y = df.ventes

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42)

Comme notre jeu de données a 200 échantillons et que l'on en réserve 20 % pour le test, on aura les tailles suivantes (  X.shape()  et  y.shape()  ) :

  • X_train: 160 * 3

  • X_test: 40 * 3

  • y_train: 160 * 1

  • y_test: 40 * 1

On a donc 160 échantillons pour entraîner notre modèle et 40 échantillons que le modèle ne voit pas pendant son entraînement et qui nous serviront à l'évaluer.

Le terme random_state est un paramètre qui permet de contrôler la reproductibilité des résultats lorsque vous effectuez des opérations qui impliquent de l'aléatoire, comme par exemple scinder les données en sous-ensembles de train et test.

En fixant une valeur spécifique pour random_state, vous vous assurez que les opérations aléatoires se déroulent toujours de la même manière. Les résultats sont reproductibles et vous pouvez comparer différents modèles.

On entraîne le modèle :

reg.fit(X_train, y_train)

Pour estimer la performance sur le sous-ensemble de test, il faut tout d'abord obtenir les prédictions pour  X_test  :

y_pred_test = reg.predict(X_test)

On peut maintenant calculer l'écart entre les vraies valeurs de test  (y_test)  et celles prédites par le modèle.

Utilisons la RMSE et la MAPE comme scores. Pour ces 2 métriques, un score plus petit correspond à un meilleur modèle. MAPE est comprise entre 0 et 1, tandis que RMSE n'est pas contrainte.

from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error
print(f"RMSE: {mean_squared_error(y_test, y_pred_test)}")
print(f"MAPE: {mean_absolute_percentage_error(y_test, y_pred_test)}")

On obtient :

  • RMSE :  3.17

  • MAPE :  0.15

Est-ce un bon ou un mauvais score ?

Difficile à dire, comme la RMSE n'est pas absolue. Une MAPE de 0,15 semble bien, car plus proche de 0 que de 1.

Mais peut-on faire mieux ?

Amélioration n° 1 : Ajouter un terme quadratique

Si l'on regarde bien le nuage de points de  ventes  par rapport à  tv  , on remarque que ce nuage de points suit plutôt une courbe qu'une ligne droite. C'est particulièrement vrai pour la partie en bas à gauche du graphe.

Nuage de points entre les variables ventes et tv, qui montre que la relation est plus quadratique que linéaire. On voit que le nuage forme davantage une courbe qu'une ligne droite.
La relation entre tv et ventes montre que la relation n'est pas linéaire

On peut en déduire que la relation entre  ventes  et  tv  n'est pas simplement linéaire, c'est-à-dire :

$\(ventes = a * tv + b\)$

Mais cela dépend aussi d'un terme $\(tv^2\)$ comme ceci :

 $\(ventes = a * tv + b * tv^2 + c\)$

C'est un polynôme du second degré de variable  tv  .

La régression polynomiale consiste à ajouter les puissances de certains prédicteurs dans la régression. C'est une façon simple pour capturer les relations non linéaires entre les variables.

Avant d'entraîner ce nouveau modèle, on remarque que l'amplitude de  tv2  va être bien plus grande que celle des autres variables. On va donc normaliser les variables, pour que leurs amplitudes soient compatibles.

Créons la nouvelle variable tv2 = tv^2 :

df['tv2'] = df.tv**2

Normalisons l'amplitude en utilisant MinMaxScaler qui force les variables entre 0 et 1.

Dans sklearn, appliquer un "Scaler" consiste à :

1. L'importer :

from sklearn.preprocessing import MinMaxScaler

2. Le créer (l'instancier) :

scaler = MinMaxScaler()

3. Le  fit()  sur les données (le scaler calcule alors les min et max des variables) :

scaler.fit(df)

4. Et enfin transformer les données :

data_array = scaler.transform(df)

La méthode  transform  retourne un  array  et non une dataframe. Pour une question de simplification des scripts, je vais recréer la dataframe  df  :

df = pd.DataFrame(data_array, columns = ['tv','radio','journaux','ventes','tv2'])

Les étapes 3 et 4 peuvent être concentrées en utilisant la méthode  fit_transform()  , ce qui donne :

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
data_array = scaler.fit_transform(df)
df = pd.DataFrame(data_array,
      columns = ['tv','radio','journaux','ventes','tv2'])

À ce stade, df ne contient que des valeurs entre 0 et 1.

df.describe().loc[['min','max']]

 

tv

radio

journaux

ventes

tv2

min

0.0

0.0

0.0

0.0

0.0

max

1.0

1.0

1.0

1.0

1.0

Notre régression linéaire est maintenant une régression polynomiale grâce à la présence du terme quadratique  tv2  . Entraînons-la.

y ~ tv + radio + journaux + tv2

Le Python :

X = df[['tv','radio','journaux', 'tv2']]
y = df.ventes

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42)

reg.fit(X_train, y_train)
y_hat_test = reg.predict(X_test)

print(f"Coefficients: {reg.coef_}")
print(f"RMSE: {mean_squared_error(y_test, y_hat_test)}")
print(f"MAPE: {mean_absolute_percentage_error(y_test, y_hat_test)}")

Ce qui donne :

modèle

normalisé

RMSE

MAPE

ventes ~ tv + radio + journaux

non

3.1741

0.15199

ventes ~ tv + radio + journaux 

oui

0.00492

0.19102

ventes ~ tv + radio + journaux + tv2

oui

0.00369

0.162

On note une nette amélioration par rapport au premier modèle.

Il est possible d'aller encore plus loin en ajoutant le terme croisé  tv * radio  qui reflète l'effet cumulé d'une campagne de pub qui soit à la fois à la radio et à la télévision.

Allez plus loin

On a parlé du paramètre random_state qui permet de contrôler l'aspect aléatoire du "train, test, split". En faisant varier ce paramètre, les données seront réparties parmi les sous-ensembles entraînement et test de façon différente et le modèle ne sera pas entraîné sur les mêmes échantillons.

Cependant imaginez que parmi le jeu de données se trouvent quelques échantillons très différents des autres. Par exemple, un très fort budget en journaux (> 200, par exemple). Si ces échantillons se retrouvent dans le sous-ensemble d'entraînement, le modèle va le prendre en compte et la droite de régression sera plus plate ou penchée que si ces échantillons se trouvaient dans le sous-ensemble de test.

Pour observer  cette sensibilité à la répartition entre train et test, ainsi que l'influence du random_state, comparez les scores obtenus au  test_size  et au  random_state  . Pour un test_size élevé (  test_size = 0.800  , le modèle aura très peu d'échantillons pour s'entraîner et sera plus sensible à la répartition des échantillons entre le test et le train.

C'est bien ce que l'on observe sur la figure suivante où l'on voit le score obtenu sur la régression  ventes ~ tv + radio + journaux  pour des valeurs décroissantes de test_size : 80 %, 60 %, 40 % et 20 %.

  • La variabilité du score est plus importante quand le nombre d'échantillons d'entraînement est faible (à gauche,  test_size  = 80 %).

  • Néanmoins, même pour un large set d'échantillons d'entraînement (à droite,  test_size  = 20 %), les scores peuvent varier fortement en fonction de la valeur de  random_state  . 

4 boxplots (boîtes à moustaches, en français) pour des valeurs croissantes de taille d'entraînement montrant l'impact du paramètre random_state.
Variation du score en fonction de random_state et du % de données d'entraînement

En résumé

  • La régression linéaire est un modèle simple pour prédire des valeurs continues en fonction de variables prédictives.

  • On évalue les performances du modèle en utilisant des métriques telles que RMSE et MAPE.

  • La normalisation des variables permet de lier les coefficients de la régression linéaire au poids relatif des prédicteurs.

  • Il est important de s'assurer que la relation entre la variable cible et les prédicteurs est linéaire avant d'utiliser la régression linéaire.

  • La régression polynomiale permet de capturer des relations non linéaires entre les variables en ajoutant des termes quadratiques ou d'ordre supérieur.

  • L'utilisation de  train_test_split  permet de diviser les données en sous-ensembles d'entraînement et de test pour évaluer le modèle.

  • Le choix du paramètre  random_state  affecte la reproductibilité des résultats lors de la séparation des données en sous-ensembles.

Dans le chapitre suivant, nous allons plonger dans la classification et ses nombreuses métriques d'évaluation.

Exemple de certificat de réussite
Exemple de certificat de réussite