cassionAnalyse de données

Leçon 4 sur 8

Unité · Comparer deux groupes

p = 0,023, et un tiers d'une journée

Les garçons sont présents à 88,77 % et les filles à 88,21 %. Sur 68 267 pointages, c'est significatif à p = 0,023. C'est aussi une différence d'un tiers de journée scolaire par enfant et par trimestre, sur laquelle aucun programme n'agirait et aucun ne devrait.

PythonR180 minDéfinitions d'indicateurs de l'UNICEFCritères d'évaluation du CAD de l'OCDE

Un résultat significatif sur lequel personne ne devrait agir

import pandas as pd
import numpy as np
from statsmodels.stats.proportion import proportions_ztest

attendance = pd.read_csv("school-attendance-2024.v1.csv")
enrolment = pd.read_csv("school-enrolment-2024.v1.csv")
current = enrolment[enrolment["school_year"] == 2024]

MARKS = {"true": True, "Y": True, "false": False, "N": False}
marked = attendance[attendance["present"].isin(MARKS)].copy()
marked["attended"] = marked["present"].map(MARKS)
marked = marked.merge(current[["student_id", "sex"]], on="student_id")

by_sex = marked.groupby("sex")["attended"].agg(["sum", "size"])
print(by_sex)

stat, p = proportions_ztest(by_sex["sum"], by_sex["size"])
print(f"z = {stat:.2f}, p = {p:.4f}")
library(dplyr)

marked |> summarise(k = sum(attended), n = n(), .by = sex)
prop.test(c(29655, 30749), c(33408, 34859))
Groupe Présences Pointages Taux
Garçons 29 655 33 408 88,77 %
Filles 30 749 34 859 88,21 %

Différence 0,56 point de pourcentage. z = 2,28, p = 0,023.

Selon la convention qu’emploie tout rapport, c’est une différence significative de présence selon le sexe. Elle passerait une relecture. Elle n’est aussi, opérationnellement, rien du tout.

Convertissez-la dans l’unité de la décision

term_days = marked["attendance_date"].nunique()
gap = 0.0056
print(f"{term_days} school days in the term")
print(f"0.56 points = {gap * term_days:.2f} days per student per term")
# The statistic is in percentage points. The decision is in days.

Soixante jours de classe, donc 0,56 % vaut 0,34 jour — environ un tiers de journée par enfant et par trimestre.

Aucune intervention sur la présence n’est conçue à cette résolution. Aucun directeur d’école ne peut agir dessus. Aucune ligne budgétaire ne bouge. Le résultat est réel, reproductible, statistiquement significatif et opérationnellement vide, et ces quatre choses sont parfaitement compatibles.

Convertissez toujours un effet dans l’unité où se prend la décision. Les points de pourcentage sont l’unité de l’analyste ; les journées, les enfants, les cas et les francs sont celle du programme.

Pourquoi p est devenu petit : c’était le n

Le p répond à « à quel point ces données seraient surprenantes s’il n’y avait aucune différence », et la surprise croît avec la taille d’échantillon à effet constant.

for scale in (0.05, 0.2, 1.0):
    k = (by_sex["sum"] * scale).round().astype(int)
    n = (by_sex["size"] * scale).round().astype(int)
    stat, p = proportions_ztest(k, n)
    print(f"n = {n.sum():>6,}  difference {k[1]/n[1] - k[0]/n[0]:+.2%}  p = {p:.3f}")
# Same proportions, smaller n, and the p-value walks back across 0.05.
Échantillon Différence p
5 % des pointages (n=3 413) +0,62 % 0,570
20 % (n=13 654) +0,55 % 0,314
100 % (n=68 267) +0,56 % 0,023

L’effet n’a jamais changé. Seul l’échantillon a changé. Un p est une affirmation sur la force de la preuve, non sur l’ampleur, et avec un échantillon assez grand toute différence devient significative.

Un p seul ne peut donc jamais vous dire si quelque chose compte. Il vous dit si vous pouvez écarter zéro, et zéro est rarement la comparaison intéressante.

Rapportez une taille d’effet à côté de chaque p

Trois mesures d’effet couvrent presque tout ce dont un rapport de programme a besoin.

Mesure Pour Se lit comme
Différence en points de pourcentage Deux proportions La réponse directe
Rapport de risques Deux proportions, événements rares Combien de fois plus probable
d de Cohen Deux moyennes Écarts-types de séparation
p_boys, p_girls = by_sex["sum"] / by_sex["size"]
print(f"difference: {p_boys - p_girls:+.2%} points")
print(f"risk ratio: {p_boys / p_girls:.3f}")
# Two lines. There is no excuse for a p-value with no effect size beside it.

Rapport de risques 1,006. Les garçons sont présents 0,6 % plus souvent en termes relatifs — une autre façon de dire le même rien.

Comparez à l’écart selon le handicap de la leçon précédente : une différence de 19,4 points et un rapport de risques de 0,58, c’est-à-dire que les cas signalant un handicap aboutissent à un peu plus de la moitié du taux. Les deux mêmes nombres, calculés de la même façon, décrivent un constat dans un cas et du bruit dans l’autre, et seule la taille d’effet les distingue.

Fixez le seuil avant de tester

La défense contre les deux erreurs — courir après un rien significatif, et écarter un quelque chose non significatif — consiste à décider d’avance quelle ampleur de différence changerait ce que vous faites.

MEANINGFUL = 0.03      # 3 points of attendance, about 1.8 days a term

observed = p_boys - p_girls
print(f"observed {observed:+.2%}, threshold {MEANINGFUL:.0%}")
print(f"large enough to act on: {abs(observed) >= MEANINGFUL}")
# Write the threshold in the analysis plan, not after seeing the result.

Trois points de présence font environ 1,8 jour par trimestre, c’est-à-dire l’échelle à laquelle un programme de suivi serait conçu. Les 0,56 observés en valent le cinquième.

Écrire MEANINGFUL avant de lancer le test est ce qui empêche le seuil de se déplacer là où le résultat est tombé. C’est la même discipline que le tableau des facteurs de confusion du cours d’épidémiologie : décidez la règle avant de voir le nombre auquel elle s’appliquera.

Les quatre cas

cases = pd.DataFrame([
    ("significant, large",     "report it",                    "disability gap, -19.4 pts"),
    ("significant, small",     "report the effect size, say it is small", "attendance by sex, 0.56 pts"),
    ("not significant, large", "report the interval; underpowered", "over-age by sex, +5.5 pts"),
    ("not significant, small", "report as no evidence of a difference", "-"),
], columns=["case", "what to do", "example in this course"])
print(cases)
# Four quadrants, and only one of them is "publish the p-value".

La troisième ligne est celle qu’on traite mal. L’écart de retard d’âge selon le sexe valait 5,5 points avec p = 0,066, et l’instinct est de rapporter « pas de différence ». Le rapport correct dit que l’étude n’a pas pu trancher une différence d’une ampleur qui aurait compté — ce qui est une affirmation sur l’échantillon, et un argument pour en prendre un plus grand plutôt que pour fermer la question.

Rapportez-le en entier

Attendance by sex, February to April 2024

  Boys    88.77%   29,655 of 33,408 marks
  Girls   88.21%   30,749 of 34,859 marks

  Difference +0.56 percentage points (p = 0.023, risk ratio 1.006).

  Equivalent to 0.34 school days per child per term. Below the 3-point
  threshold set in the analysis plan and not reported as a programme
  finding. The p-value is small because the analysis has 68,267 marks, not
  because the difference is large.

La dernière phrase est ce qui rend le bloc honnête. Un lecteur qui ne voit que « p = 0,023 » supposera que la différence compte, et la phrase qui dit pourquoi elle ne compte pas tient sur une ligne.

La suite

Chaque test jusqu’ici portait sur une comparaison. La leçon suivante en lance vingt-trois d’un coup, sur un effet qui n’existe pas, et compte combien reviennent « significatives ».

Animer cette leçon

La leçon en diaporama, la prose étant reléguée dans les notes du présentateur plutôt que projetée. Produit à partir de cette page, dont il ne peut donc pas s'écarter.

Lancer le diaporamaLire les diapositives

Le PDF ne requiert aucun logiciel et se projette depuis n'importe quel poste. Le fichier PowerPoint est fait pour être modifié : appliquez la charte de votre organisation, retirez une section pour une séance plus courte, ou fusionnez deux leçons en atelier.