---
title: "Tester une hypothèse sans perdre le sens substantiel"
---
```{r}
#| label: setup-analyse
#| include: false
source("R/04-initialiser-analyse.R")
suppressPackageStartupMessages(library(gtsummary))
```
::: {.callout-important title="Question de départ"}
Une différence observée est-elle compatible avec la variabilité d'échantillonnage, et comment éviter qu'une valeur-p remplace l'analyse de l'amplitude du résultat ?
:::
## Objectifs d'apprentissage
À la fin de ce chapitre, vous saurez :
- formuler une hypothèse nulle et une hypothèse alternative ;
- interpréter une valeur-p sans la confondre avec la probabilité que l'hypothèse nulle soit vraie ;
- choisir un test adapté à la nature de la variable et au plan d'enquête ;
- distinguer test global, contraste particulier et estimation d'amplitude ;
- articuler estimation, IC, valeur-p et importance substantielle ;
- utiliser `add_p()` lorsque le test répond réellement à la question du tableau ;
- gérer avec prudence seuils conventionnels, exploration et multiplicité.
## Une valeur-p répond à une question étroite
Sous l'hypothèse nulle et les hypothèses du test, la valeur-p mesure à quel point une statistique au moins aussi extrême que celle observée serait inhabituelle.
Elle **ne mesure pas** :
- la probabilité que $H_0$ soit vraie ;
- la probabilité que l'étude soit répliquée ;
- la taille de l'effet ;
- la pertinence sociale de la différence ;
- la plausibilité d'un mécanisme causal.
::: {.callout-warning title="Une petite valeur-p n'est pas une grande différence"}
La valeur-p dépend à la fois de l'amplitude observée et de la précision. Un écart minuscule peut être très incompatible avec $H_0$ dans une grande base ; un écart substantiellement important peut rester incertain dans un petit domaine.
:::
## Commencer par l'estimation : diplôme et pratique sportive
```{r}
#| label: tab-ch16-sport-descriptif
sport_diplome <- survey::svyby(
~sport_regulier,
~diplome_4,
design,
survey::svymean,
na.rm = TRUE,
vartype = c("se", "ci")
)
sport_df <- svyby_ci_df(sport_diplome, "sport_regulier")
sport_df |>
transmute(
`Niveau de diplôme` = diplome_4,
`Sport régulier` = fmt_pct(estimation, .1),
`IC 95 %` = paste0(fmt_pct(bas, .1), " – ", fmt_pct(haut, .1))
) |>
knitr::kable()
```
Les estimations montrent déjà la structure du résultat. Calculons maintenant le test global d'association adapté au plan :
```{r}
#| label: ch16-sport-test
test_sport <- survey::svychisq(
~diplome_4 + sport_regulier_f,
design,
statistic = "F"
)
p_low <- sport_df$estimation[sport_df$diplome_4 == "Inférieur au bac"]
p_high <- sport_df$estimation[sport_df$diplome_4 == "Supérieur long"]
diff_sport <- p_high - p_low
p_test_sport <- test_sport$p.value
tibble::tibble(
`Écart extrêmes scolaires` = fmt_pp(diff_sport, .1),
`Valeur-p globale` = fmt_p(p_test_sport)
) |>
knitr::kable()
```
L'information substantive principale est ici l'écart d'environ **`r fmt_pp(diff_sport, .1)`** entre les deux extrêmes scolaires. La valeur-p globale (`r fmt_p(p_test_sport)`) indique ensuite dans quelle mesure la table observée est compatible avec l'hypothèse d'absence d'association, sous le design et le test retenus.
::: {.callout-note title="Lecture sociologique"}
Le résultat central n'est pas « le test est significatif », mais l'existence d'un gradient scolaire de forte amplitude dans le jeu pédagogique. Dans une enquête réelle, l'étape suivante consisterait à demander dans quelle mesure ce gradient reflète ressources, santé, cycle de vie, contraintes temporelles, offre locale ou autres mécanismes. Le test ne choisit pas entre ces explications.
:::
## Test global et contrastes particuliers ne sont pas interchangeables
Une variable à quatre modalités génère plusieurs comparaisons. Un test global répond à :
> **Existe-t-il des différences quelque part entre les modalités ?**
Un contraste particulier répond à :
> **Quelle différence oppose précisément ces deux modalités ?**
Pour la satisfaction de vie, ajustons un modèle simple puis testons le terme diplôme dans son ensemble.
```{r}
#| label: tab-ch16-test-global-satisfaction
mod_sat_diplome <- survey::svyglm(
satisfaction_vie ~ diplome_4,
design = design
)
test_sat_global <- survey::regTermTest(mod_sat_diplome, ~diplome_4)
sat_diplome <- survey::svyby(
~satisfaction_vie,
~diplome_4,
design,
survey::svymean,
na.rm = TRUE,
vartype = "ci"
)
sat_df <- svyby_ci_df(sat_diplome, "satisfaction_vie")
sat_df |>
transmute(
`Niveau de diplôme` = diplome_4,
`Satisfaction moyenne` = fmt_num(estimation, .2),
`IC 95 %` = paste0(fmt_num(bas, .2), " – ", fmt_num(haut, .2))
) |>
knitr::kable()
tibble::tibble(
Question = "Effet global du diplôme",
`Valeur-p` = fmt_p(test_sat_global$p)
) |>
knitr::kable()
```
Le tableau donne l'amplitude des écarts entre catégories ; `regTermTest()` répond à la question globale de savoir si le terme diplôme apporte de l'information au modèle. Les deux sorties sont complémentaires, et aucune ne remplace l'autre.
## Deux groupes : estimation, différence et test
Prenons la satisfaction selon l'emploi. Une bonne restitution commence par les deux moyennes pondérées.
```{r}
#| label: tab-ch16-emploi-satisfaction
sat_emploi <- survey::svyby(
~satisfaction_vie,
~en_emploi,
design,
survey::svymean,
na.rm = TRUE,
vartype = c("se", "ci")
)
sat_emploi_df <- svyby_ci_df(sat_emploi, "satisfaction_vie") |>
mutate(
Groupe = if_else(en_emploi == 1, "En emploi", "Pas en emploi")
)
sat_emploi_df |>
transmute(
Groupe,
`Moyenne pondérée` = fmt_num(estimation, .2),
`IC 95 %` = paste0(fmt_num(bas, .2), " – ", fmt_num(haut, .2))
) |>
knitr::kable()
```
Puis le test :
```{r}
#| label: ch16-ttest
test_emploi <- survey::svyttest(
satisfaction_vie ~ en_emploi,
design
)
tibble::tibble(
Test = "Différence de satisfaction selon l'emploi",
`Valeur-p` = fmt_p(test_emploi$p.value)
) |>
knitr::kable()
```
L'unité d'origine — ici des points sur une échelle 0–10 — est souvent plus interprétable qu'une statistique de test. Le test répond à la compatibilité avec une différence nulle ; les moyennes indiquent **de quelle différence il s'agit**.
## Les tests de rang changent la question, ils ne suppriment pas les hypothèses
Lorsque la question porte davantage sur les rangs que sur la moyenne, `{survey}` propose `svyranktest()` :
```{r}
#| label: ch16-ranktest
rank_emploi <- survey::svyranktest(
satisfaction_vie ~ en_emploi,
design,
test = "wilcoxon"
)
tibble::tibble(
Test = "Wilcoxon adapté au plan",
`Valeur-p` = fmt_p(rank_emploi$p.value)
) |>
knitr::kable()
```
« Non paramétrique » ne signifie pas « sans hypothèses ». La statistique, le paramètre implicite et la sensibilité aux formes de distribution changent. Il faut choisir la procédure en fonction de la question, pas comme solution automatique après avoir vu un histogramme imparfait.
## Quel test pour quelle question ?
| Question | Exemple | Outil survey de départ |
|---|---|---|
| association entre deux catégorielles | diplôme × sport | `svychisq()` |
| différence de moyenne entre deux groupes | satisfaction × emploi | `svyttest()` |
| test global d'un terme à plusieurs modalités | diplôme dans un modèle | `regTermTest()` |
| comparaison fondée sur les rangs | satisfaction × emploi | `svyranktest()` |
| contraste ajusté dans un modèle | coefficient ou combinaison | `svyglm()` + contraste/IC |
Cette table est plus utile à retenir qu'une liste de seuils de valeurs-p.
## `gtsummary::add_p()` : utile lorsque table et test partagent une question
```{r}
#| label: tab-ch16-gtsummary-tests
design |>
tbl_svysummary(
by = diplome_4,
include = c(sport_regulier, satisfaction_vie),
statistic = list(
sport_regulier ~ "{p}%",
satisfaction_vie ~ "{mean} ({sd})"
),
type = sport_regulier ~ "dichotomous",
label = list(
sport_regulier ~ "Sport au moins hebdomadaire",
satisfaction_vie ~ "Satisfaction de vie (0–10)"
),
missing = "no"
) |>
add_p(
test = list(
sport_regulier ~ "svy.chisq.test",
satisfaction_vie ~ "svy.kruskal.test"
)
) |>
bold_labels()
```
::: {.callout-tip title="Quand ne pas ajouter de valeur-p ?"}
Si le tableau est purement descriptif, si des dizaines de variables sont explorées sans hypothèse préalable, si la question porte surtout sur l'ordre de grandeur, ou si le tableau sert à documenter un échantillon plutôt qu'à tester une hypothèse, une colonne de valeurs-p peut être inutile voire trompeuse.
:::
## Taille d'effet : revenir à une quantité qui a une unité
Pour une proportion, la **différence en points de pourcentage** est souvent directement lisible. Pour une moyenne, la différence dans l'unité d'origine peut l'être davantage qu'un effet standardisé.
Dans notre exemple diplôme–sport, l'écart pondéré entre supérieur long et inférieur au bac est d'environ `r fmt_pp(diff_sport, .1)`. Cette quantité indique immédiatement l'amplitude. La valeur-p ne possède aucune unité substantive.
Les effets standardisés peuvent être utiles pour comparer des échelles, mais ils ne doivent pas devenir un réflexe lorsque l'unité d'origine est déjà intelligible.
## Seuils : ne pas fabriquer une frontière scientifique
`p = 0,049` et `p = 0,051` ne représentent pas deux univers opposés. Éviter :
> « il existe un effet » / « il n'existe aucun effet »
uniquement à partir d'un seuil.
Préférer une phrase qui combine estimation et incertitude :
> « l'écart estimé est X ; son IC est [A ; B] ; la valeur-p du test global est Y. »
Le lecteur peut alors juger l'amplitude, la précision et la force de l'incompatibilité avec $H_0$ sans recevoir un verdict artificiellement binaire.
## Multiplicité : documenter l'exploration
Si l'on teste beaucoup d'hypothèses, certaines petites valeurs-p apparaîtront par hasard. Les réponses possibles dépendent du projet :
- pré-enregistrer ou hiérarchiser des hypothèses principales ;
- limiter les tests aux questions effectivement posées ;
- ajuster des valeurs-p pour une famille de tests ;
- qualifier clairement les analyses d'exploratoires ;
- privilégier estimations et IC plutôt qu'une chasse aux seuils.
Illustration simple avec Holm :
```{r}
#| label: tab-ch16-multiplicite
p_exemple <- c(.004, .018, .032, .11, .41)
tibble::tibble(
Hypothèse = paste0("H", seq_along(p_exemple)),
`p brute` = p_exemple,
`p ajustée — Holm` = p.adjust(p_exemple, method = "holm")
) |>
mutate(across(starts_with("p"), ~round(.x, 3))) |>
knitr::kable()
```
L'ajustement n'est pas une sanction automatique : il répond à la question de savoir quelle **famille d'inférences** doit être protégée contre l'accumulation de faux positifs.
## Mini-exercice
Une différence moyenne de 0,05 point sur une échelle 0–10 donne `p < 0,001`. Peut-on conclure qu'elle est importante ?
::: {.callout-caution collapse="true" title="Correction"}
Non. La valeur-p indique une forte incompatibilité avec une différence nulle dans le cadre du test, mais 0,05 point peut rester substantiellement négligeable. Il faut lire l'amplitude et son intervalle de confiance.
:::
## Exercice de synthèse
### Niveau A — Appliquer
Testez l'association diplôme–sport et la différence de satisfaction selon l'emploi avec les fonctions survey appropriées. Affichez toujours les estimations avant le test.
### Niveau B — Choisir
Pour trois comparaisons du chapitre 11, formulez explicitement $H_0$, choisissez le test et précisez la quantité substantive qui doit être présentée avant la valeur-p.
### Niveau C — Analyser
Construisez un mini-rapport d'une demi-page comprenant : un tableau descriptif, un IC, un test global, une mesure d'amplitude et une conclusion substantive sans vocabulaire causal. Indiquez enfin si les analyses sont confirmatoires ou exploratoires.
## À retenir
- Une valeur-p est conditionnelle à $H_0$ et aux hypothèses du test.
- Elle ne mesure ni la probabilité de $H_0$ ni l'importance du résultat.
- Les descriptifs et les ordres de grandeur précèdent le test.
- Le plan d'enquête doit être intégré aux tests lorsque l'inférence porte sur la population représentée [@survey2026].
- Un test global et un contraste particulier répondent à des questions différentes.
- Les seuils ne doivent pas transformer une mesure continue en verdict scientifique.
- La multiplicité concerne une famille d'inférences et doit être pensée en lien avec le statut exploratoire ou confirmatoire de l'analyse.
## Pour aller plus loin
La partie suivante passe à l'ajustement multivarié. La régression permettra de demander si un gradient reste visible **à caractéristiques observées comparables** ; elle ne transformera toujours pas automatiquement une association observationnelle en effet causal.