• 15 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 6/4/19

Analysez deux variables quantitatives par régression linéaire

Log in or subscribe for free to enjoy all this course has to offer!

Nous avons étudié au chapitre précédent la corrélation entre 2 variables quantitatives. Continuons ici avec 2 autres variables également quantitatives : attente et montant.

La variable attente est renseignée seulement pour les opérations bancaires de la catégorie COURSES. Lors d’un précédent chapitre, vous avez peut-être renseigné une catégorie COURSES sur certaines de vos opérations bancaires. Si ce n’est pas le cas, je vous invite à y refaire un tour pour y télécharger l’échantillon enrichi operations_enrichies.csv, ou bien si vous êtes motivé, à reprendre vos 20 derniers tickets de caisse pour recréer un échantillon à la main !

La variable attente d’une opération donne le nombre de jours écoulés entre celle-ci et la précédente opération de catégorie COURSES. Si vous faites vos courses tous les 7 jours en moyenne, alors la moyenne de attente sera de 7.

Que s’attend-t-on à trouver ?

En théorie, plus vous attendez pour aller faire les courses, plus vous aurez besoin d’acheter de provisions. On s’attend donc à ce que plus la valeur de attente est grande, plus la valeur du montant soit grande.

Étape préliminaire

Tout d'abord, il faut calculer la variable attente ! Je vous donne le code, vous n'avez pas forcément besoin de le comprendre :

import datetime as dt

# Selection du sous-échantillon
courses = data[data.categ == "COURSES"]

# On trie les opérations par date
courses = courses.sort_values("date_operation")

# On ramène les montants en positif
courses["montant"] = -courses["montant"]

# calcul de la variable attente
r = []
last_date = dt.datetime.now()
for i,row in courses.iterrows():
    days = (row["date_operation"]-last_date).days
    if days == 0:
        r.append(r[-1])
    else:
        r.append(days)
    last_date = row["date_operation"]
courses["attente"] = r
courses = courses.iloc[1:,]

# on regroupe les opérations qui ont été effectués à la même date
# (courses réalisées le même jour mais dans 2 magasins différents)
a = courses.groupby("date_operation")["montant"].sum()
b = courses.groupby("date_operation")["attente"].first()
courses = pd.DataFrame({"montant":a, "attente":b})

On crée ici un sous échantillon qui ne contient que les opérations de catégorie courses, et que l'on appelle...  courses  !

Modélisons !

Mais nous allons faire mieux que cela : calculer le prix moyen des produits que vous consommez en 1 jour, ainsi que la vitesse à laquelle vous accumulez du stock dans vos placards ! Pour cela, nous allons utiliser un modèle. Vous allez voir, c’est très puissant.

Pour le modèle que nous allons créer, nous allons faire plusieurs suppositions. Tout d’abord, nous supposons qu’à chaque fois que vous faites les courses, vous achetez 3 types de produits :

  1. Les produits que vous consommerez avant la prochaine fois que vous irez faire les courses (produits alimentaires, d’hygiène, etc.)

  2. Les produits qui ne seront pas consommés durant la durée de l’étude (la durée de l’étude étant la période entre votre 1er ticket de caisse enregistré dans l’échantillon et le dernier) : ce sont vos stocks de long terme (boîtes de conserves, produits surgelés, etc.)

  3. Les produits qui ne sont pas des consommables (ex : une fourchette, une serpillière, etc.), que vous n’achetez que très rarement.

Ensuite, nous supposons que vous consommez chaque jour des produits, et que le prix des produits que vous consommez en 1 jour est à peu près constant.

Appelons $\(a\)$ le prix moyen des produits consommés en un jour (ceux de type 1), et $\(b\)$ le prix moyen des produits de type 2 et 3 rassemblés que vous achetez à chaque course. Enfin, appelons $\(x\)$ le nombre de jours que vous avez attendu depuis vos dernières courses, et $\(y\)$ le montant du ticket de caisse.

Quel sera le prix de votre prochain ticket de caisse ?

Il sera égal au nombre de jours d’attente multiplié par le prix moyen ce que vous consommez en 1 jour. Mais en plus, il faut ajouter le prix moyen des produits de type 2 et 3. Ceci donne cette formule :

$\[y = a.x + b\]$

C'est un peu simpliste ton truc, mon prochain ticket ne vaudra pas exactement ce montant. Je ne consomme pas tous les jours exactement la même somme d'argent, et je n'achète pas à chaque fois la même quantité de stock ! Et imagine que j'aie envie de me faire plaisir en m'achetant des produits plus chers !

C'est vrai, c'est simpliste ! Cette équation n'est pas exacte. D'ailleurs, vous aurez peut-être remarqué qu'il s'agit d'une équation d'une droite (remémorez-vous les fonctions affines). Équation de droite signifie que si je prends tous les $\(x\)$ possibles compris entre (par exemple) 0 et 5, puis que je calcule tous leurs $\(y\)$ associés, avant de les placer sur un graphique avec les $\(x\)$ sur l'axe horizontal et les $\(y\)$ sur l'axe vertical, alors tous les points seront parfaitement alignés ! Essayons donc d'afficher le diagramme de dispersion avec X = attente et Y = montant, et regardons si tous les points sont alignés :

Ils sont loin d'être alignés ! Cela signifie que l'équation $\(y = a\dot{}x + b\)$ n'est pas tout-à-fait exacte : elle est simpliste. En écrivant cette équation, j’admets que je commettrai une certaine erreur entre la valeur que j'aurai prédite et la vraie valeur du prochain ticket. Mais je peux intégrer cette erreur à l'équation, en l'appelant $\(\epsilon\)$ (epsilon) :

$\[Y = a.X + b + \epsilon\]$

Pour calculer  $\(a\)$ et $\(b\)$ , je pourrais très bien les prendre au hasard. Mais dans ce cas, l'erreur $\(\epsilon\)$ serait souvent très grande. Ce que je souhaite, c'est me tromper le moins possible. On dit que l'on cherche à minimiser l'erreur.

Graphiquement, voici comment on peut se représenter les choses. Si je fais varier $\(a\)$ et $\(b\)$ , alors je déplace la droite sur le graphique. Minimiser l'erreur revient en fait à placer la droite dans l'alignement général des points. Voici une illustration très pédagogique, car les points sont presque dans le même alignement :

On y voit que pour un point $\(i\)$ , on cherche à ce que la différence entre le $\(y_i\)$ (qui est la vraie valeur) et le $\(\hat{y}_i\)$ (qui est la valeur prédite par mon équation inexacte $\(\hat{y}_i = a.x_i + b\)$ ) soit minimale.

Pour estimer $\(a\)$ et $\(b\)$ , l'ordinateur peut s'en charger. Pour en savoir plus, rendez-vous à la section Aller plus loin. On obtient les estimations suivantes :

  •  $\(\hat{a} = 1.74\)$

  •  $\(\hat{b} = 10.94\)$

Droite de régression d'équation y = 1.74x + 10.94
Droite de régression d'équation y = 1.74x + 10.94

Critiquons ce résultat !

Ces résultats signifient que je ne consomme que 1.74 € par jour, cela me parait peu ! De plus, 10.94€ de stock à chaque courses, c'est énorme !

C'est vrai ... à y regarder de plus près on voit qu'il a 2 points qui "sortent du lot", on les appelle des outliers. En connaissant mes propres habitudes de consommation, je sais que je ne fais jamais les courses à plus de 15 jours d'intervalle. Ces deux points, pour lesquels attente = 15 jours, correspondent en fait à des retours de vacances (durant lesquels je n'ai pas fait de courses). Comme je ne souhaite pas que ceux-ci interfèrent dans mon calcul, je les écarte.

Une fois écartés, j'obtiens ces nouvelles estimations :

  •  $\(\hat{a} = 3.03\)$

  •  $\(\hat{b} = 5.41\)$

Les 2 droites de régression (une pour chaque estimation) d'équation y=ax+b
Les 2 droites de régression (une pour chaque estimation) d'équation y=ax+b

Ce résultat est bien différent du précédent. Avec seulement 2 individus écartés, les résultats changent beaucoup. On dit donc que le traitement statistique que nous venons d'appliquer (la régression linéaire avec estimation par la méthode des moindres carrés) est peu robuste aux outliers.

Aller plus loin : Analyser la qualité du modèle

Imaginons que j'aie effacé par erreur le montant d'une opération bancaire de catégorie COURSES.

Je pourrais combler cette valeur manquante par la moyenne des montants des opérations. C'est la solution la plus basique qui soit, et vous vous imaginez qu'elle n'est pas très bonne ! Elle n'est pas très bonne car autour de la moyenne, les valeurs des montants varient, parfois de beaucoup.

Je peux alors faire mieux : je peux regarder la valeur de la variable attente de cette opération. Avec le modèle de régression linéaire que j'ai construit, je peux estimer la valeur du montant (grâce à l'équation y = ax+b). Vous vous en doutez, cette estimation sera meilleure que la précédente. En effet, quand nous avons cherché à minimiser l'erreur de modèle, nous avons en fait cherché à minimiser les variations des valeurs de montant autour de la droite de régression.

Si on avait trouvé un modèle parfait, alors il n'y aurait plus d'erreur, et donc plus de variations entre les valeurs prédites et les valeurs réelles. Dans ce cas, on dirait que le modèle a réussi à expliquer la totalité des variations. Les variations autour de la moyenne sont mesurées par la variance. Un modèle parfait aurait expliqué 100 % de la variation.

Ce pourcentage est calculé grâce à la formule de décomposition de la variance (analysis of variance, en anglais : ANOVA).

$\[SCT = SCE + SCR\]$

$\[\sum_{j=1}^{n}(y_j-\overline{y})^2 = \sum_{j=1}^n(\hat{y_j}-\overline{y})^2 + \sum_{j=1}^n(y_j-\hat{y_j})^2\]$

SCT (Somme des Carrés Totale) traduit la variation totale de Y , SCE (Somme des Carrés Expliquée) traduit la variation expliquée par le modèle et SCR (Somme des Carrés Résiduelle) traduit la variation inexpliquée par le modèle.

Pour la régression linéaire, le pourcentage de variation expliquée est donné par le coefficient de détermination noté $\(R^2\)$ :

$\[R^2 = \frac{SCE}{SCT}\]$

Aller plus loin : Estimation de $\(a\)$ et $\(b\)$

 Voici les formules qui permettent d'estimer $\(a\)$ et $\(b\)$ :

$\[\hat{a}=\frac{s_{X,Y}}{s^2_X} \ \ \ \ \ \text{et}\ \ \ \ \ \hat{b}=\overline{y}-\hat{a}\overline{x}\]$

Pourquoi les chapeaux sur a et b ?

C'est une histoire d'estimation. On considère que l'on ne peut pas avoir accès directement à vos comportements de consommation caractérisés par $\(a\)$ et $\(b\)$ , mais que l'on peut tout de même les estimer grâce à vos tickets de caisse. Ces estimations de $\(a\)$ et de $\(b\)$ sont notées $\(\hat{a}\)$ et $\(\hat{b}\)$ .

Si on rajoute à l'échantillon un nouveau ticket de caisse, celui-ci fera varier un peu $\(\hat{a}\)$  et $\(\hat{b}\)$ , même si votre comportement de consommation ne bouge pas (c'est-à-dire "même si $\(a\)$ et $\(b\)$ ne bougent pas").

 Comment estimer a et b avec du code ?

Voici comment faire. Le code est un peu complexe, mais retenez que la ligne 6 crée les variables  a  et  b  contenant les estimations.

import statsmodels.api as sm
Y = courses['montant']
X = courses[['attente']]
X = X.copy() # On modifiera X, on en crée donc une copie
X['intercept'] = 1.
result = sm.OLS(Y, X).fit() # OLS = Ordinary Least Square (Moindres Carrés Ordinaire)
a,b = result.params['attente'],result.params['intercept']

Pourquoi y a t'il un simple crochet ligne 2 e un double crochet ligne 3 ?

Une régression linéaire prédit une variable en fonction d'une ou plusieurs variables.  sm.OLS  s'attend donc à trouver une unique colonne (c-à-d un  pd.Series  ) en premier argument (ici Y), mais s'attend à trouver potentiellement plusieurs colonnes en 2nd argument (ici X, qui est un  pd.DataFrame  ). Pour sélectionner plusieurs colonnes d'un dataframe, on passe une liste de noms de colonnes. Et comme une liste s'écrit entre crochets, ceux-ci viennent s'ajouter aux crochets déjà présents !

Pour afficher la droite, il faut faire comme ceci :

plt.plot(courses.attente,courses.montant, "o")
plt.plot(np.arange(15),[a*x+b for x in np.arange(15)])
plt.xlabel("attente")
plt.ylabel("montant")
plt.show()

La ligne 1 affiche le graphique de dispersion.

En ligne 2,  np.arange  crée une liste de nombres entiers allant de 0 à 14 :  [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]  .

On place cette liste en abscisse. Pour chacune de ces 15 valeurs, on calcule les ordonnées grâce à la formule y=ax+b comme ceci :  [a*x+b for x in np.arange(15)]  . On vient donc de créer une série de points tous alignés sur la droite d'équation y=ax+b. La ligne 2 affiche tous ces points, en les reliant entre eux, ce qui nous donne une belle ligne !

Example of certificate of achievement
Example of certificate of achievement