Régression polynomiale avec python

Dans notre précédent article Créer Un Modèle De Régression Linéaire Avec Python, nous avons présenté de façon générale la régression linéaire. Nous aborderons dans cet article le cas de la régression polynomiale.

Pour rappel : La régression linéaire est un modèle (analyse) qui a pour but d’établir une relation linéaire entre une variable  (appelée variable expliquée) par une ou plusieurs autres variables (appelées variables explicatives). Par exemple, il peut exister une relation linéaire entre le salaire d’une personne et le nombre d’années passées à l’université.

Alors la question est de savoir si notre modèle de régression linéaire sera autant performant s’il n’existe pas de relation linéaire entre la variable expliquée et le ou les variable(s) expliquée(s) ?

Plan de l’article

Dans cet article nous allons aborder les points suivants

  • Le problème de la régression linéaire
  • La Régression polynomiale
  • l’Over-fitting et l’Under-fitting
  • La régression polynomiale avec python

Le problème de la régression linéaire

L’une des grandes hypothèses de la régression linéaire est bien évidement l’existence d’une relation de linéaire entre les variables expliquées (y) et  explicatives (x). Le problème est que rien n’est vraiment linéaire (une pensée pour Gallilé…) . Illustrons nos dires au travers d’un exemple.

Dans l’exemple suivant nous allons générer un jeu de données où la relation entre les variables explicatives et expliquées n’est pas linéaire.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(color_codes=True)
plt.rcParams["figure.figsize"] = [12,12]

#plt.figure(figsize=(12,12))


np.random.seed(0)
#jeu de données sous la forme y = f(x)  avec f(x) = x^4 + bx^3 + c 

x = np.random.normal(10, 2, 500)
y = x ** 4 + np.random.uniform(-1, 1,500)*(x ** 3) + np.random.uniform(0, 1,500)

plt.scatter(x,y)
plt.show()

Jeu de données aléatoire non linéaire

Ensuite, appliquons à notre jeu de données un modèle de régression linéaire afin de tracer la droite de régression.

x = x[:, np.newaxis]
y = y[:, np.newaxis]
from sklearn.linear_model import LinearRegression
model = LinearRegression()

model.fit(x,y)
y_predict = model.predict(x)

plt.scatter(x, y)
plt.plot(x, y_predict, color='g')
plt.show()


Aussi, on voit que notre modèle de régression nous donnera de mauvaises prédictions car nous avons un mauvais ajustement de notre de régression. Dans ce cas, on aura une erreur de prédiction assez élevée.
C’était évident mais l’idée était de montrer que la régression linéaire n’est pas forcément adaptée à tous les problèmes de régression.

Afin d’améliorer notre modèle de régression, penser aux polynômes est une très bonne idée ! Pourquoi ? Je vous mets de la lecture sur la théorie de l’approximation polynomiale.🙃
Bref d’où l’idée de la régression polynomiale.

La Régression polynomiale

La régression polynomiale est une forme d’analyse de régression dans laquelle la relation entre la variable explicative et la variable expliquée est modélisée comme un polynôme.
Petit rappel : La régression linéaire est une régression polynomiale de degré 1.
Alors pourquoi se limiter à  un polynôme de degré 1 ?🙈

Si on prend l’exemple de la régression linéaire simple où la relation entre la variable expliquée et la variable explicative peut s’écire comme suit :

l’idée de la régression polynomiale sera d’écrire cette relation comme suit:

(ou n est le dégré du polynôme)

Si on reprend notre précédent exemple en utilisant cette fois-ci une relation polynomiale on s’aperçoit que l’erreur de prédiction est moins élevée et que notre droite de régression s’ajuste mieux à nos données.

from sklearn.preprocessing import PolynomialFeatures

polynomial_features= PolynomialFeatures(degree=4)
x_poly = polynomial_features.fit_transform(x)

model = LinearRegression()
model.fit(x_poly, y)
y_poly_pred = model.predict(x_poly)

rmse = np.sqrt(mean_squared_error(y,y_poly_pred))
#r2 = r2_score(y,y_poly_pred)
print(rmse)
#print(r2)
import operator
plt.scatter(x, y, s=10)
# sort the values of x before line plot
sort_axis = operator.itemgetter(0)
sorted_zip = sorted(zip(x,y_poly_pred), key=sort_axis)
x_p, y_poly_pred_P = zip(*sorted_zip)
plt.plot(x_p, y_poly_pred_P, color='g')
plt.show()

plot régression polynomiale

Comprendre l’Over-fitting et l’Under-fitting

Une question qu’on peut se poser est : comment se fait le choix du degré du polynôme dans la régression polynomiale ? Nous allons profiter de cette question pour aborder deux notions très très très très importantes que sont l’under-fitting et l’over-fitting.

Nous allons tracer la courbe de l’erreur quadratique en fonction du degré du polynôme.

def degreeChoice (x,y,degree):
    polynomial_features= PolynomialFeatures(degree=degree)
    x_poly = polynomial_features.fit_transform(x)
    model = LinearRegression()
    model.fit(x_poly, y)
    y_poly_pred = model.predict(x_poly)
    rmse = np.sqrt(mean_squared_error(y,y_poly_pred))
    sort_axis = operator.itemgetter(0)
    sorted_zip = sorted(zip(x,y_poly_pred), key=sort_axis)
    x_p, y_poly_pred_P = zip(*sorted_zip)
    return rmse, x_p, y_poly_pred_P

rmselist = np.zeros(100)
x_p_list = [None]*100
y_poly_pred_P_list=[None]*100
for i in np.arange(1, 101):
    
    rmselist[i-1] ,x_p_list[i-1],y_poly_pred_P_list[i-1]= degreeChoice (x,y,i)
    
plt.plot(np.arange(1, 101), rmselist, color='r')
plt.show()
régression polynomiale - EQM en fonction du dégré
On s’aperçoit que l’erreur de prédiction de notre modèle diminue considérablement jusqu’au degré 20 puis augmente subitement pour les ordres supérieurs. Regardons ça de plus près.
fig, axs = plt.subplots(3, 2,figsize=(20,20))


axs[0, 0].scatter(x, y)
axs[0, 0].plot(x_p_list[0],y_poly_pred_P_list[0],color='g')
axs[0, 0].set_title('Regression linéaire simple')

#degre 2
axs[0, 1].scatter(x, y)
axs[0, 1].plot(x_p_list[1],y_poly_pred_P_list[1],color='g')
axs[0, 1].set_title('Regression polynomiale deg 2')


#degre 4
axs[1, 0].scatter(x, y)
axs[1, 0].plot(x_p_list[3],y_poly_pred_P_list[3],color='g')
axs[1, 0].set_title('Regression polynomiale deg 4')


#degre 16
axs[1, 1].scatter(x, y)
axs[1, 1].plot(x_p_list[15],y_poly_pred_P_list[15],color='g')
axs[1, 1].set_title('Regression polynomiale deg 16')

#degre 32
axs[2, 0].scatter(x, y)
axs[2, 0].plot(x_p_list[31],y_poly_pred_P_list[31],color='g')
axs[2, 0].set_title('Regression polynomiale deg 32')

#degre 64
axs[2, 1].scatter(x, y)
axs[2, 1].plot(x_p_list[63],y_poly_pred_P_list[63],color='g')
axs[2, 1].set_title('Regression polynomiale deg 64')
for ax in axs.flat:
    ax.set(xlabel='x', ylabel='y')

for ax in axs.flat:
    ax.label_outer()
régression polynomiale avec différents degré
Lorsqu’on fait un plot de notre modèle pour différents degrés du polynôme de régression. On se rend compte qu’on obtient un bon modèle de régression avec un degré=4.
Pour les degrés assez élèves (ex degré=64) notre modèle semble assez étrange. En effet, il s’agit là d’un exemple d’overfitting (ou de sur-ajustement).
Le overfitting d’un modèle est une condition dans laquelle un modèle commence à décrire l’erreur aléatoire (le bruit ) dans les données plutôt que les relations entre les variables. Ce problème se produit lorsque le modèle est trop complexe.
Dans l’autre sens, l’underfitting  (ou sous-ajustement ) se produit lorsqu’un modèle ne peut pas saisir correctement la structure sous-jacente des données. Notre premier modèle en est un exemple.
Afin d’obtenir le modèle optimal, un compromis entre le biais  et la variance du modèle s’impose.

La régression polynomiale avec python

Afin d’illustrer la régression polynomiale sur un vrai dataset, nous allons améliorer le modèle de prédiction des prix de maison créé dans l’article sur la régression linéaire.

Petit rappel:

Le jeu de données utilisé  était le Boston Housing Dataset qui contient un bon nombre de données sur l’immobilier à Boston (prix, superficie, …).
L’objectif sera de prédire le prix des maisons (variable expliquée) grâce aux différentes informations présentes dans le jeu de données (variables explicatives). L’analyse des données ayant déjà été faite dans cet article, nous passons directement à création du modèle.

#on importe les libs et les données 
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score
from sklearn.preprocessing import PolynomialFeatures
from sklearn.datasets import load_boston
donnees_boston = load_boston()

#Transformation de notre jeu de données en Data Frame grace à pandas
donnees_boston_df = pd.DataFrame(donnees_boston.data, columns=donnees_boston.feature_names)

#on utilise seulement 4 variables explicatives
X=pd.DataFrame(np.c_[donnees_boston_df['LSTAT'],donnees_boston_df['RM'],donnees_boston_df['TAX'],donnees_boston_df['PTRATIO']], columns = ['LSTAT','RM','TAX','PTRATIO'])
Y = donnees_boston_df['PRIX']
 
#base d'apprentissage et base de test
from sklearn.model_selection import train_test_split
 
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.2, random_state=5)
print(X_train.shape)
print(X_test.shape)
print(Y_train.shape)
print(Y_test.shape)
#on defintit la fonction pour entrainer et choisir notre modèle en fonction du degré du polynome

def evalPolynonmialRegression(degree):
    #entrainement du modèle
    polynomial_features= PolynomialFeatures(degree=degree)
    X_train_poly = polynomial_features.fit_transform(X_train)
    X_test_poly = polynomial_features.fit_transform(X_test)
    model = LinearRegression()
    model.fit(X_train_poly, Y_train)
    # Evaluation du training set

    y_train_predict = model.predict(X_train_poly)
    rmse = (np.sqrt(mean_squared_error(Y_train, y_train_predict)))
    r2 = r2_score(Y_train, y_train_predict)

    print('La performance du modèle sur la base dapprentissage')
    print('--------------------------------------')
    print('Lerreur quadratique moyenne est {}'.format(rmse))
    print('le score R2 est {}'.format(r2))
    print('\n')

    # Evaluation du testing set
    y_test_predict = model.predict(X_test_poly)
    rmse = (np.sqrt(mean_squared_error(Y_test, y_test_predict)))
    r2 = r2_score(Y_test, y_test_predict)

    print('La performance du modèle sur la base de test')
    print('--------------------------------------')
    print('Lerreur quadratique moyenne est {}'.format(rmse))
    print('le score R2 est {}'.format(r2))
    return model,r2 ,rmse

Alors, on execute la fonction avec un degré=4.

evalPolynonmialRegression(4)

Nous obtientenons bien évidemment un meilleur modèle.

 
La performance du modèle sur la base dapprentissage
--------------------------------------
Lerreur quadratique moyenne est 2.90954689132934
le score R2 est 0.9014517366633048


La performance du modèle sur la base de test
--------------------------------------
Lerreur quadratique moyenne est 3.457159901752652
le score R2 est 0.8473449481539901

Ressources complémentaires

Le Notebook de l’article
La doc de sklearn sur les différentes méthodes de regression
L’underfitting
L’Overfitting

Petit Récap

En somme, nous avons présenté dans cet article la regression polynomiale. En effet la différence entre la regression polynomiale et a regression linéaire est l’utilisation d’un polynome pour décrire la relation entre les variables. Nous avons pu aborder dans la foulée les notions de d’overfitting et de underfitting. N’hesitez pas à laisser des commentaires pour les questions et suggestions.

 

1 commentaire
  1. Olivier dit

    Article interessant

Laisser un commentaire

Votre adresse email ne sera pas publiée.

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

Voulez-vous en savoir plus sur la Data Science ?

Inscrivez-vous alors à notre newsletter et vous receverez gratuitement nos derniers articles et actualités ! 
S'INSCRIRE MAINTENANT 
close-link