Afficher le code R
design_reg <- subset(
design,
!is.na(satisfaction_vie) &
!is.na(diplome_4) &
!is.na(age) &
!is.na(sexe_f) &
!is.na(en_emploi) &
!is.na(revenu_k) &
!is.na(sante_f)
)
n_reg <- nrow(design_reg$variables)Le gradient de satisfaction de vie observé selon le diplôme reste-t-il du même ordre de grandeur lorsque l’on tient compte de l’âge, du sexe, de l’emploi, du revenu et de la santé ?
À la fin de ce chapitre, vous saurez :
svyglm() pour tenir compte du plan ;{gtsummary} ;Le chapitre 11 a montré une satisfaction moyenne légèrement plus élevée dans les catégories de diplôme supérieures. Mais les groupes scolaires diffèrent aussi par l’âge, le revenu, la santé et d’autres caractéristiques.
Une régression linéaire décrit l’espérance conditionnelle :
\[ E(Y|X) = \beta_0 + \beta_1 X_1 + \cdots + \beta_p X_p. \]
Un coefficient indique comment varie la moyenne conditionnelle de \(Y\) lorsque la variable considérée change, pour les valeurs données des autres variables incluses dans le modèle.
« Toutes choses égales par ailleurs dans le modèle » signifie seulement que les variables incluses sont maintenues constantes statistiquement. Cela ne garantit ni absence de confusion résiduelle, ni temporalité correcte, ni absence de médiateurs ou de biais de sélection.
Un piège classique consiste à comparer deux coefficients alors que l’ajout d’une variable a aussi supprimé des observations. On ne sait plus si le coefficient change à cause de l’ajustement ou parce que l’échantillon n’est plus le même.
Pour suivre proprement M1 à M4, nous définissons donc une seule fois l’échantillon complet sur toutes les variables du modèle final, puis nous réestimons chaque spécification sur ce même domaine.
design_reg <- subset(
design,
!is.na(satisfaction_vie) &
!is.na(diplome_4) &
!is.na(age) &
!is.na(sexe_f) &
!is.na(en_emploi) &
!is.na(revenu_k) &
!is.na(sante_f)
)
n_reg <- nrow(design_reg$variables)Le parcours de modèles porte ainsi sur 3 050 observations à chaque étape. Les descriptifs du chapitre 11, eux, utilisaient toute l’information disponible variable par variable : les deux stratégies répondent à des objectifs différents.
m1 <- survey::svyglm(
satisfaction_vie ~ diplome_4,
design = design_reg
)Avec « Inférieur au bac » comme référence, les coefficients des autres catégories sont des différences de satisfaction moyenne par rapport à ce groupe.
m2 <- survey::svyglm(
satisfaction_vie ~ diplome_4 + age + sexe_f,
design = design_reg
)Le coefficient d’âge est exprimé pour une année. Si cette unité paraît trop fine, on pourrait exprimer l’âge en décennies ou centrer l’âge autour de 45 ans.
Le revenu est exprimé en milliers d’euros dans revenu_k, variable construite avant la création du design.
m3 <- survey::svyglm(
satisfaction_vie ~ diplome_4 + age + sexe_f + en_emploi + revenu_k,
design = design_reg
)Le coefficient de revenu_k s’interprète alors comme la différence moyenne de satisfaction associée à 1 000 € de revenu mensuel supplémentaires, à valeurs égales des autres variables du modèle.
m4 <- survey::svyglm(
satisfaction_vie ~ diplome_4 + age + sexe_f + en_emploi + revenu_k + sante_f,
design = design_reg
)L’état de santé est très fortement lié au bien-être déclaré. Son ajout permet ici de demander si le gradient scolaire reste visible à santé déclarée comparable.
Pour la comparaison des modèles, nous suivons un seul contraste : « supérieur long » versus « inférieur au bac ». L’objectif n’est pas de masquer les autres coefficients — le tableau final les donnera — mais de visualiser ce qui arrive à l’association qui motive la séquence.
resume_contraste <- function(modele, nom_modele) {
terme <- grep("Supérieur long", names(stats::coef(modele)), value = TRUE)[1]
ci <- stats::confint(modele)[terme, ]
tibble::tibble(
Modèle = nom_modele,
beta = as.numeric(stats::coef(modele)[terme]),
bas = as.numeric(ci[1]),
haut = as.numeric(ci[2])
)
}
progression <- dplyr::bind_rows(
resume_contraste(m1, "M1 · diplôme"),
resume_contraste(m2, "M2 · + âge, sexe"),
resume_contraste(m3, "M3 · + emploi, revenu"),
resume_contraste(m4, "M4 · + santé")
) |>
dplyr::mutate(Modèle = factor(Modèle, levels = Modèle))
knitr::kable(
progression |>
dplyr::transmute(
Spécification = Modèle,
`β supérieur long vs inférieur au bac` = fmt_num(beta, .01),
`IC 95 %` = paste0("[", fmt_num(bas, .01), " ; ", fmt_num(haut, .01), "]")
),
align = c("l", "r", "c")
)| Spécification | β supérieur long vs inférieur au bac | IC 95 % |
|---|---|---|
| M1 · diplôme | 0,43 | [0,25 ; 0,60] |
| M2 · + âge, sexe | 0,34 | [0,16 ; 0,52] |
| M3 · + emploi, revenu | 0,03 | [-0,17 ; 0,23] |
| M4 · + santé | 0,05 | [-0,14 ; 0,24] |
ggplot(progression, aes(x = beta, y = forcats::fct_rev(Modèle))) +
geom_vline(xintercept = 0, linetype = 2, colour = couleurs_enqueter[["gris"]]) +
geom_errorbarh(
aes(xmin = bas, xmax = haut),
height = .10, linewidth = .65,
colour = couleurs_enqueter[["gris"]]
) +
geom_point(size = 3, colour = couleurs_enqueter[["principal"]]) +
labs(
x = "Différence de satisfaction (points, IC 95 %)",
y = NULL,
title = "Le gradient scolaire s'atténue surtout après l'introduction des ressources économiques",
subtitle = "Même échantillon analytique dans les quatre spécifications",
caption = "Contraste : supérieur long versus inférieur au bac ; données synthétiques EnquêteR."
) +
theme_enqueter()
Sur ce même échantillon, l’écart entre les deux extrêmes du diplôme est d’environ 0,43 point dans M1. Il tombe à 0,03 dans M3 et reste proche de 0,05 dans M4. L’essentiel de l’atténuation se produit donc au moment où l’emploi et le revenu entrent dans le modèle.
Cette lecture est plus solide que la comparaison de quatre sorties indépendantes : comme le nombre d’observations est fixé, la trajectoire du coefficient reflète bien le changement de spécification, et non un mélange de spécification et de sélection des cas complets.
Dans une enquête réelle, cette atténuation orienterait l’interprétation vers les ressources et positions sociales associées au diplôme plutôt que vers une relation autonome entre titre scolaire et bien-être. Ici, revenu et emploi captent une partie de ces différences ; la santé en modifie peu davantage le contraste scolaire. Cela ne suffit pas à établir une chaîne causale, mais cela aide à formuler plus précisément ce que le modèle rend plausible.
Dire que « le revenu explique l’effet du diplôme » serait trop fort. Dans une coupe transversale, revenu, emploi, santé et diplôme peuvent être liés par plusieurs chemins causaux et processus de sélection. La séquence M1–M4 est une décomposition descriptive conditionnelle, pas une analyse de médiation.
Tableau 17.2. Associations ajustées avec la satisfaction de vie
tbl_m4 <- tbl_regression(
m4,
intercept = FALSE,
label = list(
diplome_4 ~ "Niveau de diplôme",
age ~ "Âge (années)",
sexe_f ~ "Sexe / genre",
en_emploi ~ "En emploi",
revenu_k ~ "Revenu mensuel (+1 000 €)",
sante_f ~ "État de santé déclaré"
)
) |>
bold_labels()
tbl_m4| Caractéristique | Beta | 95% IC | p-valeur |
|---|---|---|---|
| Niveau de diplôme | |||
| Inférieur au bac | — | — | |
| Bac | 0,12 | -0,03 – 0,27 | 0,10 |
| Bac+2 | 0,15 | -0,01 – 0,30 | 0,061 |
| Supérieur long | 0,05 | -0,14 – 0,24 | 0,6 |
| Âge (années) | 0,00 | 0,00 – 0,00 | 0,8 |
| Sexe / genre | |||
| Homme | — | — | |
| Femme | 0,03 | -0,06 – 0,12 | 0,5 |
| Autre / non-binaire | 0,00 | -0,44 – 0,44 | >0,9 |
| En emploi | 0,06 | -0,09 – 0,21 | 0,5 |
| Revenu mensuel (+1 000 €) | 0,29 | 0,18 – 0,39 | <0,001 |
| État de santé déclaré | |||
| Très bonne | — | — | |
| Bonne | -0,40 | -0,58 – -0,22 | <0,001 |
| Moyenne | -0,85 | -1,0 – -0,67 | <0,001 |
| Mauvaise | -1,4 | -1,7 – -1,1 | <0,001 |
| Très mauvaise | -2,2 | -3,0 – -1,3 | <0,001 |
| Abréviation: IC = intervalle de confiance | |||
Le tableau doit être lu en unités originales : points de satisfaction sur une échelle 0–10. Une différence de 0,1 ou 0,3 point doit être jugée sur cette échelle, pas seulement via sa valeur-p.
Pour une variable catégorielle à quatre modalités, trois coefficients séparés ne répondent pas à la question « le diplôme est-il associé globalement au résultat ? ». Un test conjoint est plus approprié :
test_diplome_m4 <- survey::regTermTest(m4, ~diplome_4)
tibble::tibble(
Terme = "Niveau de diplôme — test global",
`Valeur-p` = fmt_p(test_diplome_m4$p)
) |>
knitr::kable(align = c("l", "r"))| Terme | Valeur-p |
|---|---|
| Niveau de diplôme — test global | 0,209 |
Ce test complète les coefficients ; il ne remplace ni leur ordre de grandeur ni les prédictions ci-dessous.
Comparons quatre profils identiques sauf pour le diplôme : 45 ans, femme, en emploi, revenu de 2 200 €, santé bonne.
profils_sat <- tibble(
diplome_4 = factor(
levels(enqueter$diplome_4),
levels = levels(enqueter$diplome_4)
),
age = 45,
sexe_f = factor("Femme", levels = levels(enqueter$sexe_f)),
en_emploi = 1,
revenu_k = 2.2,
sante_f = factor("Bonne", levels = levels(enqueter$sante_f))
)
pred_sat <- predict(m4, newdata = profils_sat, se.fit = TRUE)
pred_sat_ci <- ci_design(
est = as.numeric(coef(pred_sat)),
se = as.numeric(SE(pred_sat)),
design = design_reg
)
pred_sat_df <- profils_sat |>
mutate(
prediction = as.numeric(coef(pred_sat)),
se = as.numeric(SE(pred_sat)),
bas = pred_sat_ci[, "bas"],
haut = pred_sat_ci[, "haut"]
)ggplot(pred_sat_df, aes(x = prediction, y = diplome_4)) +
geom_errorbarh(
aes(xmin = bas, xmax = haut),
height = .12,
colour = couleurs_enqueter[["gris"]]
) +
geom_point(size = 3.2, colour = couleurs_enqueter[["principal"]]) +
scale_x_continuous(limits = c(5.5, 8.5)) +
labs(
x = "Satisfaction moyenne prédite (0–10, IC 95 %)",
y = NULL,
title = "Après ajustement, le gradient scolaire de satisfaction devient faible",
subtitle = "Profil : 45 ans, femme, en emploi, revenu 2 200 €, santé bonne",
caption = "Intervalles pour la moyenne conditionnelle prédite, fondés sur les degrés de liberté du plan ; données synthétiques."
) +
theme_enqueter()
Cette figure est souvent plus parlante que quatre coefficients : elle montre directement la petite amplitude résiduelle du contraste scolaire lorsque le profil est fixé.
Une inspection graphique précède le choix de la forme :
ggplot(enqueter, aes(age, satisfaction_vie, weight = poids_final)) +
geom_jitter(alpha = .08, width = .2, height = .05, na.rm = TRUE) +
geom_smooth(
method = "loess",
se = TRUE,
colour = couleurs_enqueter[["principal"]],
fill = couleurs_enqueter[["gris_clair"]],
na.rm = TRUE
) +
labs(
x = "Âge",
y = "Satisfaction de vie",
title = "Inspecter la forme avant d'imposer une droite",
subtitle = "Lissage descriptif pondéré par le poids final"
) +
theme_enqueter()
Si une courbure paraît substantielle, on peut comparer une spécification avec terme quadratique ou spline. Les coefficients age et age² deviennent alors difficiles à lire isolément ; on privilégie les prédictions.
tibble::tibble(
Étape = c("Fichier analytique", "Échantillon commun M1–M4", "Observations écartées"),
N = c(nrow(enqueter), n_reg, nrow(enqueter) - n_reg)
) |>
knitr::kable(align = c("l", "r"))| Étape | N |
|---|---|
| Fichier analytique | 3592 |
| Échantillon commun M1–M4 | 3050 |
| Observations écartées | 542 |
Le revenu explique une grande partie de la réduction d’effectif. C’est précisément pourquoi nous avons fixé l’échantillon avant de comparer les modèles. Le chapitre 21 reviendra sur cette sélection par cas complets et montrera comment l’imputation multiple peut être utilisée comme analyse de sensibilité.
Si le coefficient de revenu_k vaut 0,30, comment l’interpréter ?
À caractéristiques incluses dans le modèle comparables, 1 000 € de revenu mensuel supplémentaires sont associés à environ 0,30 point supplémentaire de satisfaction de vie. Cette formulation reste associationnelle.
Reproduisez M1 à M4 et vérifiez comment évoluent les coefficients du diplôme.
Proposez une autre séquence de modèles et justifiez l’ordre d’introduction des variables en termes substantifs, non en fonction de leurs valeurs-p.
Rédigez 200 mots répondant à : « Le diplôme est-il associé à la satisfaction de vie ? ». Votre texte doit distinguer descriptif brut, association ajustée, rôle possible du revenu et de la santé, et limites causales.
svyglm() utilise le plan d’enquête pour l’inférence (Lumley et al. 2026).Le chapitre suivant traite une réponse binaire. Nous en profiterons pour montrer qu’une bonne régression logistique commence par définir correctement l’univers analytique avant de calculer des odds ratios.