18  Régression logistique : définir l’univers avant d’interpréter les odds ratios

ImportantQuestion de départ

Comment modéliser une probabilité binaire sans confondre odds, probabilité et causalité — et pourquoi la définition de la population analysée peut-elle compter davantage que la sophistication du modèle ?

18.1 Objectifs d’apprentissage

À la fin de ce chapitre, vous saurez :

  • expliquer pourquoi une réponse binaire appelle un modèle adapté ;
  • distinguer probabilité, odds, log-odds et odds ratio ;
  • définir un univers analytique cohérent avant estimation ;
  • comparer des modèles sur un échantillon commun ;
  • modéliser une relation non linéaire avec l’âge et tester la contribution du terme quadratique ;
  • présenter les OR avec {gtsummary} ;
  • traduire le modèle en probabilités prédites ;
  • séparer clairement résultat conditionnel, structure de cycle de vie et interprétation causale.

18.2 L’emploi : un exemple où le champ d’analyse change le sens du modèle

en_emploi vaut 1 pour les personnes en emploi et 0 pour les autres situations. Si l’on analyse tous les 18–79 ans dans une seule régression, l’âge mélange :

  • entrée dans la vie active ;
  • chômage et inactivité ;
  • activité en milieu de carrière ;
  • sortie du marché du travail ;
  • retraite.

Un coefficient linéaire unique d’âge serait alors très facile à surinterpréter.

ImportantDéfinir l’univers avant la formule

Pour l’exemple principal, nous limitons l’analyse aux 25–64 ans. Ce choix ne constitue pas une règle générale : il correspond à la question « être en emploi parmi les adultes d’âge actif ». Une autre question — par exemple l’activité après 60 ans — demanderait un autre champ.

18.3 Construire une base analytique commune

Avant de comparer des modèles, imposons la même disponibilité de données pour toutes les variables qu’ils utiliseront. Nous évitons ainsi qu’une différence entre modèles provienne en réalité d’un changement d’échantillon.

Afficher le code R
vars_modele <- c("en_emploi", "age", "diplome_4", "sexe_f")

cc_work <- enqueter |>
  filter(age >= 25, age <= 64) |>
  filter(if_all(all_of(vars_modele), ~ !is.na(.x))) |>
  pull(id)

design_work <- subset(design, id %in% cc_work)
design_work <- update(design_work, age_c = age - 45)

n_univers <- sum(enqueter$age >= 25 & enqueter$age <= 64, na.rm = TRUE)
n_cc <- nrow(design_work$variables)

tibble::tibble(
  Étape = c("Personnes de 25–64 ans", "Échantillon analytique commun"),
  `N non pondéré` = c(n_univers, n_cc),
  `Part conservée` = c(1, n_cc / n_univers)
) |>
  mutate(`Part conservée` = fmt_pct(`Part conservée`, .1)) |>
  knitr::kable()
Étape N non pondéré Part conservée
Personnes de 25–64 ans 2840 100,0%
Échantillon analytique commun 2738 96,4%

Cette table sépare deux décisions : restriction de champ et exclusion pour données manquantes. Les confondre rendrait la description de l’échantillon du modèle difficile à reproduire.

18.4 Avant la régression : quelle structure observe-t-on ?

Afficher le code R
emploi_diplome <- survey::svyby(
  ~en_emploi,
  ~diplome_4,
  design_work,
  survey::svymean,
  na.rm = TRUE,
  vartype = c("se", "ci")
)

emploi_df <- svyby_ci_df(emploi_diplome, "en_emploi")

emploi_df |>
  transmute(
    `Niveau de diplôme` = diplome_4,
    `En emploi` = fmt_pct(estimation, .1),
    `IC 95 %` = paste0(fmt_pct(bas, .1), " – ", fmt_pct(haut, .1))
  ) |>
  knitr::kable()
Niveau de diplôme En emploi IC 95 %
Inférieur au bac Inférieur au bac 68,3% 65,6% – 70,9%
Bac Bac 68,2% 64,3% – 72,2%
Bac+2 Bac+2 69,2% 63,6% – 74,7%
Supérieur long Supérieur long 72,7% 69,2% – 76,2%

Le gradient scolaire d’emploi est ici moins marqué que les gradients observés pour le sport, les revenus ou la lecture. Ce constat est substantif : un même marqueur social n’organise pas toutes les dimensions avec la même intensité.

18.5 Pourquoi pas une régression linéaire ?

Pour une variable binaire, une droite peut produire des prédictions inférieures à 0 ou supérieures à 1 et impose une structure de variance inadaptée. La régression logistique modélise :

\[ \log\left(\frac{p}{1-p}\right) = X\beta. \]

Le terme de gauche est le logit de la probabilité. Les coefficients sont donc d’abord des différences de log-odds ; leur exponentielle donne des odds ratios.

18.6 Probabilité, odds et odds ratio

Si \(p = 0{,}75\), les odds valent :

\[ \frac{0{,}75}{0{,}25} = 3. \]

Les odds sont donc « trois contre un ». Un odds ratio compare les odds entre deux situations.

AvertissementOR ≠ risque relatif ≠ différence de probabilité

Un OR de 2 ne signifie pas que la probabilité double. La traduction dépend du niveau de probabilité de départ. C’est l’une des raisons pour lesquelles les prédictions sur l’échelle 0–1 sont souvent préférables pour communiquer le résultat.

18.7 Linéarité de l’âge : une hypothèse qu’il faut regarder

Sur l’échelle du logit, un modèle simple imposerait un changement constant par année d’âge. Comparons cette spécification à une forme quadratique sur le même échantillon.

Afficher le code R
mod_age_lin <- survey::svyglm(
  en_emploi ~ diplome_4 + age_c + sexe_f,
  design = design_work,
  family = quasibinomial()
)

mod_age_quad <- survey::svyglm(
  en_emploi ~ diplome_4 + age_c + I(age_c^2) + sexe_f,
  design = design_work,
  family = quasibinomial()
)

test_courbure <- survey::regTermTest(mod_age_quad, ~I(age_c^2))
Afficher le code R
tibble::tibble(
  Spécification = c("Âge linéaire", "Âge + âge²"),
  `N modèle` = c(nobs(mod_age_lin), nobs(mod_age_quad)),
  `Même échantillon ?` = c("Oui", "Oui")
) |>
  knitr::kable()
Spécification N modèle Même échantillon ?
Âge linéaire 2738 Oui
Âge + âge² 2738 Oui

Le terme quadratique ne doit pas être interprété isolément comme un « effet de l’âge² ». Il sert à autoriser une courbure. Le test du terme vérifie si cette flexibilité supplémentaire est soutenue par les données dans le cadre du modèle.

La valeur-p du test de courbure est < 0,001. Quel que soit le seuil choisi, la lecture principale restera graphique : quelle forme de probabilité le modèle implique-t-il sur l’âge actif ?

18.8 Tableau d’odds ratios : utile mais incomplet

Afficher le code R
mod_logit <- mod_age_quad

tbl_regression(
  mod_logit,
  exponentiate = TRUE,
  label = list(
    diplome_4 ~ "Niveau de diplôme",
    age_c ~ "Âge centré à 45 ans",
    `I(age_c^2)` ~ "Âge²",
    sexe_f ~ "Sexe / genre"
  )
) |>
  bold_labels()
Caractéristique OR 95% IC p-valeur
Niveau de diplôme


    Inférieur au bac
    Bac 0,95 0,76 – 1,18 0,6
    Bac+2 0,98 0,71 – 1,36 >0,9
    Supérieur long 1,15 0,91 – 1,44 0,2
Âge centré à 45 ans 0,97 0,97 – 0,98 <0,001
Âge² 1,00 1,00 – 1,00 <0,001
Sexe / genre


    Homme
    Femme 1,09 0,89 – 1,32 0,4
    Autre / non-binaire 0,69 0,36 – 1,33 0,3
Abréviations: IC = intervalle de confiance, OR = rapport de cotes

Les OR du diplôme comparent des personnes de même âge et de même sexe dans la spécification retenue. Les deux termes d’âge doivent être lus ensemble : les exponentier séparément ne produit pas une description intuitive de la trajectoire prédite.

18.9 Revenir sur l’échelle des probabilités

Construisons des profils de femmes de 25 à 64 ans pour chaque niveau de diplôme. Les intervalles utilisent les degrés de liberté du design plutôt qu’un 1,96 codé en dur.

Afficher le code R
ages_pred <- seq(25, 64, by = 3)

profils_emploi <- tidyr::expand_grid(
  age = ages_pred,
  diplome_4 = factor(
    levels(enqueter$diplome_4),
    levels = levels(enqueter$diplome_4)
  )
) |>
  mutate(
    age_c = age - 45,
    sexe_f = factor("Femme", levels = levels(enqueter$sexe_f))
  )

pred_emploi <- predict(
  mod_logit,
  newdata = profils_emploi,
  type = "response",
  se.fit = TRUE
)

ci_pred <- ci_estimation(
  coef(pred_emploi),
  SE(pred_emploi),
  design_work,
  lower = 0,
  upper = 1
)

profils_emploi <- bind_cols(
  profils_emploi,
  ci_pred |>
    transmute(
      probabilite = estimation,
      se,
      bas,
      haut
    )
)
Afficher le code R
ggplot(
  profils_emploi,
  aes(x = age, y = probabilite, colour = diplome_4, group = diplome_4)
) +
  geom_ribbon(
    aes(ymin = bas, ymax = haut, fill = diplome_4),
    alpha = .06,
    colour = NA
  ) +
  geom_line(linewidth = 1) +
  scale_colour_manual(values = palette_enqueter[1:4]) +
  scale_fill_manual(values = palette_enqueter[1:4]) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1), limits = c(0, 1)) +
  labs(
    x = "Âge",
    y = "Probabilité prédite d'être en emploi",
    colour = "Diplôme",
    fill = "Diplôme",
    title = "L'emploi au cours de l'âge actif n'est pas bien résumé par une pente unique",
    subtitle = "Prédictions conditionnelles pour sexe = femme",
    caption = "Jeu synthétique ; probabilités issues du modèle survey, sans interprétation causale."
  ) +
  theme_enqueter()

Courbes de probabilités prédites d'emploi selon l'âge pour quatre niveaux de diplôme, avec bandes d'incertitude.

La figure fait apparaître la structure que les coefficients rendent difficile à résumer : l’emploi est élevé sur une partie de l’âge actif puis décroît à l’approche de la sortie d’activité. Les courbes de diplôme peuvent être comparées, mais l’écart scolaire est ici moins massif que dans d’autres dimensions du jeu synthétique.

18.10 Un tableau de profils pour ne pas dépendre uniquement de la figure

Afficher le code R
profils_emploi |>
  filter(age %in% c(31, 46, 61)) |>
  transmute(
    Âge = age,
    Diplôme = diplome_4,
    `Probabilité prédite` = fmt_pct(probabilite, .1),
    `IC 95 %` = paste0(fmt_pct(bas, .1), " – ", fmt_pct(haut, .1))
  ) |>
  knitr::kable()
Âge Diplôme Probabilité prédite IC 95 %
31 Inférieur au bac 73,9% 69,6% – 78,2%
31 Bac 72,9% 68,2% – 77,5%
31 Bac+2 73,5% 68,1% – 79,0%
31 Supérieur long 76,5% 72,1% – 80,8%
46 Inférieur au bac 75,3% 71,7% – 78,9%
46 Bac 74,3% 69,3% – 79,2%
46 Bac+2 74,9% 68,8% – 81,0%
46 Supérieur long 77,7% 73,6% – 81,8%
61 Inférieur au bac 52,8% 47,0% – 58,6%
61 Bac 51,4% 44,9% – 58,0%
61 Bac+2 52,3% 43,5% – 61,1%
61 Supérieur long 56,2% 49,2% – 63,1%

Le tableau et la figure servent deux usages différents : la figure montre la forme ; le tableau permet de citer quelques ordres de grandeur précis dans le texte.

NoteLecture sociologique

L’emploi est ici fortement structuré par le cycle de vie professionnel. L’âge ne doit pas être lu comme une caractéristique individuelle abstraite : il renvoie à des transitions institutionnelles, scolaires et professionnelles. Les différences de diplôme restent conditionnelles à ce champ 25–64 ans et à la définition binaire « en emploi / pas en emploi », qui agrège chômage, inactivité et autres situations.

AvertissementCe que nous ne pouvons pas conclure

Une courbe d’emploi selon l’âge dans une enquête transversale ne décrit pas la trajectoire d’une même personne. Âge, génération, conjoncture et sélection peuvent se superposer. Le modèle ajuste des associations observées ; il n’identifie pas un effet causal de vieillir.

18.11 Catégories de référence et stabilité du modèle

Changer la référence du diplôme change les OR affichés mais pas les probabilités prédites par le modèle. La référence doit être choisie pour rendre le contraste lisible, non pour obtenir une valeur-p particulière.

Lorsque plusieurs modèles sont comparés, conserver la même référence et le même échantillon facilite également la lecture de la progression des coefficients.

18.12 Mini-exercice

Un OR vaut 1,8 pour une catégorie de diplôme. Quelle formulation faut-il éviter ?

Éviter « la probabilité est 80 % plus élevée ». On peut dire que les odds sont multipliées par 1,8, conditionnellement au modèle, puis utiliser les probabilités prédites pour communiquer l’ordre de grandeur sur l’échelle 0–1.

18.13 Exercice de synthèse

18.13.1 Niveau A — Appliquer

Estimez les modèles linéaire et quadratique d’âge sur le même échantillon 25–64 ans. Présentez les OR du modèle retenu avec leurs IC.

18.13.2 Niveau B — Choisir

Expliquez pourquoi le modèle tous âges et le modèle 25–64 ans ne répondent pas exactement à la même question, même s’ils utilisent la même variable dépendante.

18.13.3 Niveau C — Analyser

Produisez des probabilités prédites pour plusieurs âges et diplômes. Rédigez un résultat distinguant : champ analytique, forme du cycle de vie, gradient scolaire, incertitude et absence de causalité.

18.14 À retenir

  • Une réponse binaire demande un modèle adapté à l’échelle des probabilités.
  • L’univers analytique doit être défini avant le modèle.
  • Les modèles comparés doivent, autant que possible, être estimés sur le même échantillon analytique.
  • Un OR n’est ni une probabilité ni une différence de probabilités.
  • Les formes non linéaires doivent être interprétées conjointement et idéalement avec des prédictions.
  • svyglm(..., family = quasibinomial()) permet une inférence tenant compte du plan (Lumley et al. 2026).
  • Un modèle techniquement correct peut rester substantiellement mal posé si le champ analysé ne correspond pas à la question.

18.15 Pour aller plus loin

Le prochain chapitre introduit les interactions : l’association estimée d’une variable peut elle-même varier selon l’âge, le diplôme ou une autre caractéristique.