Une régression qui sait que les lignes vont par groupes : plusieurs mois d'un même magasin, plusieurs élèves d'une même classe. On estime un effet commun à tous, comme celui d'une promotion, et un écart propre à chaque groupe. Les groupes peu observés empruntent de l'information aux autres au lieu d'être jugés sur trois chiffres.
Un recruteur qui évalue un commercial arrivé il y a trois mois. Il ne le juge pas sur ses trois seuls mois : il part de la moyenne de l'équipe et ajuste selon ce qu'il a vu.
Les effets fixes valent pour tous, comme l'effet d'une promotion. Les effets aléatoires sont des écarts propres à chaque groupe, supposés tirés d'une même distribution.
Le modèle mesure combien les magasins diffèrent vraiment entre eux, une fois le bruit de chaque mois retiré.
L'écart d'un magasin est ramené vers la moyenne, d'autant plus qu'il a peu d'historique. Un magasin de 24 mois garde presque son écart brut, un magasin de 3 mois beaucoup moins.
Le CA mensuel de 40 magasins, avec une indicatrice de promotion. La plupart ont 24 mois d'historique, quelques ouvertures récentes seulement 3. Les données sont simulées, avec un effet promo fixé à +12 k€.
Le modèle donne l'effet moyen de la promotion, en tenant compte du niveau propre à chaque magasin. Il classe aussi les magasins sans surestimer une ouverture récente qui a connu trois bons mois.
Deux lectures clés : l'écart-type entre magasins comparé à l'écart-type résiduel, qui dit si l'effet magasin compte, et la comparaison des écarts bruts et estimés, qui montre le rétrécissement des magasins récents.
Noms donnés pour R (lme4) et Python (statsmodels).
Un niveau propre à chaque magasin : l'intercept aléatoire. C'est le point de départ, qui suffit dans bien des cas.
Un effet promo qui varie d'un magasin à l'autre : la pente aléatoire. À ajouter si le métier pense que la promo marche mieux dans certains magasins.
REML (défaut) donne de meilleures variances. Pour comparer deux modèles aux effets fixes différents, on réestime par maximum de vraisemblance (REML = FALSE).
(1 | region / magasin) pour des magasins dans des régions. Des groupes croisés, comme clients et produits, se gèrent très bien en R avec lme4, moins facilement en Python.
# Effet des promotions sur 40 magasins : modèle mixte en R
library(lme4)
# Simulation : 40 magasins, dont quelques ouvertures récentes (3 mois d'historique)
set.seed(42)
nb_mois <- sample(c(24, 3), 40, replace = TRUE, prob = c(0.8, 0.2))
magasin <- rep(1:40, times = nb_mois)
effet_magasin <- rnorm(40, 0, 25) # écart propre à chaque magasin (k€)
promo <- rbinom(length(magasin), 1, 0.3) # mois avec promotion
ca <- 150 + effet_magasin[magasin] + 12 * promo + rnorm(length(magasin), 0, 40)
donnees <- data.frame(magasin = factor(magasin), promo = promo, ca = ca)
# Effet fixe : la promo. Effet aléatoire : le niveau de chaque magasin
modele <- lmer(ca ~ promo + (1 | magasin), data = donnees)
print(summary(modele)) # effet promo et variance entre magasins
# Écart de chaque magasin : brut vs estimé par le modèle (rétréci s'il a peu de mois)
brut <- tapply(donnees$ca, donnees$magasin, mean) - mean(donnees$ca)
ecarts <- data.frame(mois = nb_mois, ecart_brut = round(brut, 1),
ecart_modele = round(ranef(modele)$magasin[, 1], 1))
print(ecarts[ecarts$mois == 3, ])
# Effet des promotions sur 40 magasins : modèle mixte en Python
import numpy as np
import pandas as pd
import statsmodels.formula.api as smf
# Simulation : 40 magasins, dont quelques ouvertures récentes (3 mois d'historique)
rng = np.random.default_rng(42)
nb_mois = rng.choice([24, 3], size=40, p=[0.8, 0.2])
magasin = np.repeat(np.arange(40), nb_mois)
effet_magasin = rng.normal(0, 25, 40) # écart propre à chaque magasin (k€)
promo = rng.binomial(1, 0.3, len(magasin)) # mois avec promotion
ca = 150 + effet_magasin[magasin] + 12 * promo + rng.normal(0, 40, len(magasin))
donnees = pd.DataFrame({"magasin": magasin, "promo": promo, "ca": ca})
# Effet fixe : la promo. Effet aléatoire : le niveau de chaque magasin
modele = smf.mixedlm("ca ~ promo", donnees, groups=donnees["magasin"]).fit(reml=True)
print(modele.summary()) # effet promo et variance entre magasins
# Écart de chaque magasin : brut vs estimé par le modèle (rétréci s'il a peu de mois)
brut = donnees.groupby("magasin")["ca"].mean() - donnees["ca"].mean()
estime = pd.Series({k: v.iloc[0] for k, v in modele.random_effects.items()})
ecarts = pd.DataFrame({"mois": nb_mois, "ecart_brut": brut.round(1), "ecart_modele": estime.round(1)})
print(ecarts[ecarts["mois"] == 3])
Un effet fixe est un paramètre estimé tel quel, comme l'effet d'une promotion. Un effet aléatoire est un écart propre à chaque groupe, supposé tiré d'une distribution commune dont on estime la variance. Cette hypothèse permet de rétrécir les écarts des groupes peu observés.
Un magasin avec trois mois d'historique donnerait un modèle très instable. Le modèle mixte estime un seul modèle, partage l'information entre magasins et n'ajuste chaque magasin que dans la mesure où ses données le justifient.
Souvent, oui. Quand un même client, patient ou magasin apparaît plusieurs fois, ses lignes ne sont pas indépendantes. Une régression classique sous-estime alors les marges d'erreur. L'effet aléatoire du groupe corrige ce problème.
Ignore que les lignes d'un même magasin se ressemblent : effets mal estimés et marges d'erreur trop optimistes.
Voir la fiche → pour d'autres loisLe GLM mixte (glmer) ajoute des effets aléatoires à une régression logistique ou de Poisson.
Voir la fiche → le même rétrécissementUn effet aléatoire revient à une pénalité Ridge sur les écarts de groupe, dont la force est estimée sur les données.
Voir la fiche →Dataistudio forme les équipes au machine learning et à l'IA, sur des cas concrets.
Nous utilisons des cookies de mesure d'audience et de suivi publicitaire pour comprendre la fréquentation du site et l'efficacité de nos annonces. Rien n'est déposé sans votre accord. En savoir plus