Leçon 1 sur 8
Unité · Un modèle est une comparaison
Le coefficient est l'écart
Ajustez la présence sur une seule indicatrice de cantine. La constante vaut 85,21 % — la moyenne des écoles sans programme. Le coefficient vaut 4,94 points — l'écart entre les deux moyennes, à la quatrième décimale. Une régression à une indicatrice est une comparaison de deux groupes, rien de plus.
La même comparaison, écrite deux fois
Le cours de statistiques a comparé la présence dans les écoles avec cantine à celle des écoles sans, et a obtenu 90,15 % contre 85,21 %. Ajustez cela comme une régression et regardez ce qui revient.
import pandas as pd
import numpy as np
import statsmodels.formula.api as smf
attendance = pd.read_csv("school-attendance-2024.v1.csv")
roster = pd.read_csv("school-roster-2024.v1.csv").drop_duplicates(
"student_id", keep="last") # two never-de-registered transfers
MARKS = {"true": True, "Y": True, "false": False, "N": False}
marked = attendance[attendance["present"].isin(MARKS)].copy()
marked["attended"] = marked["present"].map(MARKS)
per_student = (marked.groupby("student_id")["attended"].mean()
.rename("rate").reset_index()
.merge(roster, on="student_id"))
model = smf.ols("rate ~ feeding_programme", data=per_student).fit()
print(model.summary().tables[1])
library(dplyr)
per_student |> lm(rate ~ feeding_programme, data = _) |> summary()
| Terme | Coefficient | ET | t |
|---|---|---|---|
| Constante | 0,8521 | 0,0070 | 121,30 |
feeding_programme[True] |
0,0494 | 0,0088 | 5,63 |
means = per_student.groupby("feeding_programme")["rate"].mean()
print(means)
print(f"difference: {means[True] - means[False]:.4f}")
per_student |> summarise(rate = mean(rate), .by = feeding_programme)
Moyenne sans programme : 0,8521. Avec : 0,9015. Écart : 0,0494.
La constante est le premier nombre et le coefficient le troisième, exactement. Ce n’est ni une approximation ni une coïncidence — avec un seul prédicteur binaire et rien d’autre, les moindres carrés n’ont aucune latitude pour faire autre chose que reproduire les deux moyennes de groupe.
Ce que signifie chaque terme
Trois phrases couvrent toute la lecture d’un tableau de coefficients, et elles valent pour chaque modèle de ce cours.
La constante est la valeur ajustée quand tous les prédicteurs valent zéro. Ici
c’est feeding_programme = False, donc la constante est la moyenne des écoles sans
programme. Ce n’est pas « la présence moyenne » et ce n’est une référence en aucun
sens programmatique — c’est la moyenne d’un groupe précis, et lequel dépend
entièrement du codage des prédicteurs.
Un coefficient est la variation du résultat pour une variation d’une unité de ce prédicteur, les autres étant maintenus fixes. Pour une indicatrice, « une unité » vaut False → True, donc le coefficient est un écart entre deux groupes.
Une erreur-type est la même erreur-type que celle calculée au cours précédent.
La colonne t vaut le coefficient sur l’erreur-type, et l’intervalle vaut le
coefficient plus ou moins environ deux erreurs-types. Rien de neuf n’est introduit.
coef = model.params["feeding_programme[T.True]"]
se = model.bse["feeding_programme[T.True]"]
print(f"{coef:+.4f} 95% CI [{coef - 1.96*se:+.4f}, {coef + 1.96*se:+.4f}]")
confint(model)
+0,0494, IC à 95 % +0,0322 à +0,0665 — le même intervalle, atteint depuis les mêmes données par un autre chemin.
Où les deux chemins diffèrent, et de combien
Le t de la régression vaut 5,63 et le test t de Welch du cours de statistiques donnait 5,41. Cette différence n’est une erreur ni de l’un ni de l’autre.
Les moindres carrés ordinaires supposent une seule variance résiduelle pour les deux groupes. C’est le test t à variance commune écrit sous forme matricielle. Le test de Welch ne la suppose pas, ce qui est la raison pour laquelle le cours précédent recommandait Welch par défaut.
from scipy import stats
fed = per_student[per_student["feeding_programme"]]["rate"]
unfed = per_student[~per_student["feeding_programme"]]["rate"]
print(f"variances: {fed.var():.5f} and {unfed.var():.5f}")
print("pooled t:", stats.ttest_ind(fed, unfed).statistic.round(2))
print("Welch t:", stats.ttest_ind(fed, unfed, equal_var=False).statistic.round(2))
t.test(rate ~ feeding_programme, data = per_student, var.equal = TRUE)
t.test(rate ~ feeding_programme, data = per_student)
La régression reproduit exactement le t à variance commune. Quand les variances de groupe sont proches les deux diffèrent à peine ; ici elles valent 0,019 et 0,025, et l’écart est la raison d’être de Welch. On ne peut pas demander « Welch » à une régression — le remède est une erreur-type robuste, que la leçon 6 introduit pour une raison voisine.
Trois prédicteurs, trois lectures
L’utilité d’une régression commence quand le prédicteur n’est pas binaire. Chaque type se lit différemment et chacun est une comparaison.
| Prédicteur | Le coefficient se lit |
|---|---|
Binaire (feeding_programme) |
L’écart entre les deux groupes |
Continu (age_years) |
La variation par année |
| Catégoriel à k niveaux | k−1 coefficients, chacun un écart contre le niveau omis |
enrolment = pd.read_csv("school-enrolment-2024.v1.csv")
current = enrolment[enrolment["school_year"] == 2024]
joined = per_student.merge(
current[["student_id", "sex", "age_years", "admin2"]], on="student_id")
print(smf.ols("rate ~ admin2", data=joined).fit().params.round(4))
print(joined.groupby("admin2")["rate"].mean().round(4))
lm(rate ~ admin2, data = joined) |> coef()
joined |> summarise(rate = mean(rate), .by = admin2)
Un prédicteur catégoriel produit un coefficient par niveau sauf un, et chaque coefficient est une comparaison contre ce niveau omis. Changez le niveau omis et chaque nombre de la colonne change alors que le modèle est identique — premier signe qu’un coefficient ne signifie rien sans savoir à quoi il est comparé.
Énoncez le niveau de référence dans la légende du tableau. « Contre Artibonite » fait deux mots et c’est la différence entre un tableau lisible et un tableau que le lecteur doit deviner.
Ce que le modèle ne dit pas
Deux choses qu’un coefficient ne porte jamais, et que les lecteurs fournissent d’eux-mêmes.
Ce n’est pas un effet. Le coefficient de 4,9 points est l’écart entre deux ensembles d’écoles qui n’ont pas été randomisées vers une cantine. Chaque régression de ce cours est une comparaison de groupes qui différaient déjà ; la leçon 5 porte sur celles de ces différences que vous pouvez et ne pouvez pas retirer.
Ce n’est pas une prédiction qui vaille la peine. La régression est enseignée ailleurs comme une machine à prédire, et pour des données de programme ce cadrage fait des dégâts : il invite à comparer des modèles par leur ajustement plutôt que par la question de savoir si la comparaison est celle dont le rapport a besoin. Ajustez le modèle qu’implique votre question, puis lisez le coefficient pour lequel il a été ajusté, et traitez le R² comme un diagnostic et non comme une note — la leçon 8 porte sur un modèle de R² 0,03 qui est le constat le plus utile de son rapport.
Rapportez-le en entier
Attendance and school feeding, February to April 2024
Linear model, one predictor, 1,200 students.
Intercept (no programme) 85.21%
Feeding programme +4.94 points 95% CI +3.22 to +6.65
The coefficient is the difference between the two group means and is
reported as such. Schools were not randomised into the programme; the
comparison is observational.
The standard error assumes independent students. It is not, and lesson 6
gives the corrected version.
La dernière ligne est une reconnaissance de dette que le cours honore, et l’écrire vaut mieux que d’ignorer qu’elle est due. Un modèle rapporté avec une réserve que vous savez nommer se porte mieux qu’un modèle rapporté sans.
La suite
Un prédicteur reproduit une comparaison que vous auriez pu faire sans modèle. La leçon suivante ajoute le deuxième prédicteur, là où une régression commence à gagner sa place — et où « ajuster sur » reçoit un sens précis, plus étroit que ce que supposent la plupart des rapports.