• 10 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 03/05/2019

Programmez votre première régression linéaire

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

La régression linéaire est un premier exemple simple de la manière dont un algorithme peut apprendre un modèle. Pour franchir le pas, je vous propose maintenant de l'aborder en pratique, donc à vos claviers !

Installez les logiciels utilisés

Vous aurez besoin d’installer scikit-learn pour coder l’exemple en même temps que moi. 

Je vous recommande aussi d’utiliser un notebook Jupiter, pratique pour afficher vos résultats au fur et à mesure directement dans un navigateur web.

Définissez la problématique et ses données d'entraînement

Reprenons notre problématique des loyers abordée dans le premier chapitre de ce cours. La question qu'on essaie de résoudre est :

Étant donné les caractéristiques de mon appartement, combien devrais-je normalement payer mon loyer ?

Imaginons pour l'instant que la seule caractéristique dont nous disposons est la surface de l'appartement. Notre training set est un ensemble de N = 545 observations de surface et leur loyer associé :  $\((x, y) = (\text{surface}, \text{loyer})\)$ .

Commençons par charger et afficher les données d'entraînement, juste pour avoir une meilleure idée de ce à quoi on a affaire :

# On importe les librairies dont on aura besoin pour ce tp
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# On charge le dataset
house_data = pd.read_csv('house.csv')

# On affiche le nuage de points dont on dispose
plt.plot(house_data['surface'], house_data['loyer'], 'ro', markersize=4)
plt.show()

Répartition des loyers sous forme de droite
Répartition des loyers sous forme de droite

Clairement d'après la visualisation, on peut se dire que le montant du loyer dépend de manière linéaire de la surface du logement. On peut donc émettre une hypothèse de modélisation qui est que le phénomène possède la forme d'une droite. 

Aussi, on peut voir que lorsque la surface devient un peu trop grande, les données semblent devenir moins modélisables facilement, il y a plus de variabilité. On va considérer pour l'instant résoudre le problème de prédiction pour les loyers inférieurs à 10,000€, afin de conserver une robustesse du modèle à ces données plutôt anormales, qui correspondent peut être à un autre modèle distinct ou un traitement comme outliers.

house_data = house_data[house_data['loyer'] < 10000]

Reformulez le problème dans l'espace d’hypothèse : une droite

La régression linéaire s’appuie sur l’hypothèse que les données proviennent d’un phénomène qui a la forme d'une droite, c’est-à-dire qu’il existe une relation linéaire entre l’entrée (les observations) et la sortie (les prédictions).

Nous avons donc notre contrainte de modèle sous-jacent qui doit être sous la forme $\(\hat{y} = x^T\theta\)$  avec  $\(x^T = (x_1, x_2, x_3, ..., x_N), \hat{y}^T = (\hat{y_1}, \hat{y_2}, \hat{y_3}, ..., \hat{y_N})\)$   

Où N est le nombre d'observation à notre disposition (id est le nombre d'appartements considérés dans notre cas).

En général, une observation a plusieurs variables qui la caractérise (un appartement est par exemple caractérisé par une surface et un nombre de pièces). Donc une observation est caractérisée par un vecteur  $\(x_i^T=(1, v^i_1, v^i_2, ..., v^i_D)\)$   avec D le nombre de variables caractérisant l'observation.

Dans notre cas, puisqu’on est en une dimension,  $\(D=1\)$ , donc on peut écrire pour un observation  $\(i\)$    $\(\hat{y_i} =x_i^T\theta =\theta_0 + \theta_1 \times v^i_1\)$ 

où  $\(v^i_1\)$ représente la surface pour du $\(ième\)$ appartement de notre échantillon de taille $\(N\)$  .

Notre objectif est donc de trouver la droite paramétrée par $\(\theta = (\theta_0, \theta_1)\)$ qui fitte le mieux aux données d’entraînement.

Définissez la fonction loss

Pour effectuer une régression linéaire, on doit ensuite choisir une fonction de perte dont on a parlé dans le chapitre précédent. On ne va pas prendre de risque, on va prendre la distance euclidienne. 😉

La distance euclidienne d'une observation $\(y_i\)$  vis-à-vis de notre modèle $\(\hat{y}_i\)$  est :

$\(\vert\vert \hat{y}_i - y_i \vert\vert_2 = \vert\vert x^T_i\theta - y_i \vert\vert_2\)$

Le risque empirique dont on parlait dans le chapitre précédent est donc, pour N observations : 

  $\(E = \sum_{i=1}^N \vert\vert x_i^T\theta - y_i \vert\vert_2\)$  

Et on va donc chercher à trouver le $\(\theta\)$ qui minimise cette fonction de perte (qu’on note E) :

$\(\hat{\theta} = \text{argmin}_{\theta} E\)$

Apprentissage : trouvez le $\(\theta\)$ optimal

Pour la régression linéaire, la solution de l'équation de minimisation (juste au-dessus) est exacte :

  $\(\hat{\theta} = (X^TX)^{-1}X^Ty\)$  

Pourtant vous parliez, dans le chapitre précédent, d'algorithme itératif qui convergeait vers une solution non ? Là on a une solution exacte directement en fait ?

Alors en l’occurence on a de la chance. 😅 Il existe bien une solution exacte dans ce cas précis, qu’on vient de donner. Mais on peut aussi utiliser un algorithme appelé descente de gradient pour trouver une approximation de la solution. C'est en particulier utile lorsqu'on a beaucoup de données d'exemples, car c'est assez long pour un ordinateur de calculer la solution exacte ci-dessus (on calcule un inverse de matrice, ce qui n'est pas gratuit en temps de calcul !).

Bon en tout cas, on peut maintenant calculer les paramètres directement :

# On décompose le dataset et on le transforme en matrices pour pouvoir effectuer notre calcul
X = np.matrix([np.ones(house_data.shape[0]), house_data['surface'].as_matrix()]).T
y = np.matrix(house_data['loyer']).T

# On effectue le calcul exact du paramètre theta
theta = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)

print(theta)

On trouve donc la valeur numérique de $\(\theta\)$ pour nos données :

[[ 266.45460292]
 [ 30.66119596]]

Notre modèle final qui colle bien aux données sera donc dans notre cas (approximativement) :

$\(\text{loyer} = 30.7 \times \text{surface} + 266.4\)$

On peut représenter graphiquement la droite qu'on a trouvée pour vérifier qu'elle colle bien aux données :

plt.xlabel('Surface')
plt.ylabel('Loyer')

plt.plot(house_data['surface'], house_data['loyer'], 'ro', markersize=4)

# On affiche la droite entre 0 et 250
plt.plot([0,250], [theta.item(0),theta.item(0) + 250 * theta.item(1)], linestyle='--', c='#000000')

plt.show()
Notre régression linéaire
Notre régression linéaire

Utilisez le modèle pour effectuer des prédictions

Maintenant qu’on a notre paramètre $\(\theta\)$, c’est-à-dire qu’on a trouvé la droite qui colle le mieux à nos données d’entraînement, on peut effectuer des prédictions sur de nouvelles données, c'est-à-dire prédire le loyer en fonction de la surface qu’on nous donne en entrée, en appliquant directement la formule du modèle ci-dessus.

Par exemple, si on l’applique pour une surface de 35m carrés :

theta.item(0) + theta.item(1) * 35

On obtient une estimation du loyer :

1339.646166

Essayez avec n'importe quelle surface !

En résumé

  • À partir d'une problématique et d'un dataset, nous avons considéré une hypothèse de travail pour contraindre le modèle : ici nous nous sommes placés dans le cas d'une régression linéaire, qui signifie contraindre la forme du modèle à une droite.

  • Nous avons décomposé l'entraînement de ce modèle sur les observations, afin de déterminer le paramètre (pente et ordonnée à l'origine) de la droite optimale pour ces données. C'est cette partie que l'on appelle apprentissage du modèle.

  • À l'aide du modèle ainsi trouvé, nous avons effectué des prédictions de montant de loyer à partir de n'importe quelle surface donnée.

Allez plus loin : le “vrai” travail de modélisation

Maintenant qu’on a trouvé un premier modèle, il serait possible de tester plein d’hypothèses différentes pour aller plus loin et améliorer ses performances.

Que se passe-t-il si : 

  • on change l’hypothèse de linéarité (une droite) et qu’on en prend une autre (un polynôme du second degré par exemple) ?

  • on teste le modèle avec d’autres types d’erreurs que la distance euclidienne ?

  • on ajoute des features (dimensions) supplémentaires en entrée ?

  • au fur et à mesure que la surface augmente, les données ont l'air d'être de plus en plus "éparses" : comment intégrer ce comportement dans ma modélisation ?

Toutes ces questions peuvent (et devraient !) être testées. Trouver la configuration la plus pertinente revient du coup à tester les différents modèles (régression linéaire ou non linéaire, dimensions différentes, et tous les autres algorithmes que l'on verra par la suite) qui en découlent et trouver celui qui convient le mieux en termes de performance...

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