cassionAnalyse de données

Retour à la leçonLeçon 3 sur 8Comparer deux groupes

Deux écarts, deux réponses

Le même diaporama que les téléchargements, rendu sous forme de page. Lancez le diaporama pour le présenter en plein écran — les flèches ou un clic avancent d'une diapositive, Échap quitte.

Diapositives · PDFDiapositives · PowerPoint

  1. Diapositive 1 / 25

    Ce que couvre cette leçon

    • Les deux questions que le module 4 a reportées
    • Écart numéro un : celui qui n'y est pas
    • Écart numéro deux : celui qui y est
    • Les deux résultats côte à côte
    • Choisir le test
    • Vérifiez les hypothèses, et dites que vous l'avez fait
    • Rapportez la différence, non les deux nombres
    • La suite
    Notes du présentateur
    Un écart de 5,5 points avec un intervalle de −0,4 à +11,3, et un écart de 19,4 points avec un intervalle de −26,1 à −12,8. Même test, même code, conclusions opposées — et le module 4 avait laissé les deux ouverts exprès.
  2. Diapositive 2 / 25

    Les deux questions que le module 4 a reportées — En Python

    import pandas as pd
    import numpy as np
    from statsmodels.stats.proportion import proportions_ztest, confint_proportions_2indep
    
    enrolment = pd.read_csv("school-enrolment-2024.v1.csv")
    clean = enrolment[(enrolment["age_years"] <= 20)
                      & (enrolment["school_year"] == 2024)
                      & enrolment["grade"].between(1, 6)]
    clean = clean.assign(over_age=clean["age_years"] > clean["grade"] + 5)
    
    boys = clean[clean["sex"] == "m"]["over_age"]
    girls = clean[clean["sex"] == "f"]["over_age"]
    print(f"boys  {boys.sum()}/{len(boys)} = {boys.mean():.1%}")
    print(f"girls {girls.sum()}/{len(girls)} = {girls.mean():.1%}")
    Notes du présentateur
    Le cours d'éducation a trouvé les garçons plus souvent en retard d'âge que les filles et a refusé d'en faire un constat. Le cours de protection a trouvé un écart d'aboutissement selon le handicap et l'a qualifié de résultat le plus important du jeu de données. Les deux disaient « calculez d'abord l'intervalle ». Voici ce calcul.
  3. Diapositive 3 / 25

    Les deux questions que le module 4 a reportées — En R

    library(dplyr)
    
    enrolment |>
      filter(age_years <= 20, school_year == 2024, between(grade, 1, 6)) |>
      mutate(over_age = age_years > grade + 5) |>
      summarise(k = sum(over_age), n = n(), .by = sex)
  4. Diapositive 4 / 25

    Écart numéro un : celui qui n'y est pas

    GroupeRetard d'âgenIntervalle à 95 %
    Garçons39,2 %51035,1–43,5 %
    Filles33,8 %54229,9–37,8 %
  5. Diapositive 5 / 25

    Écart numéro un : celui qui n'y est pas — En Python

    count = np.array([boys.sum(), girls.sum()])
    nobs = np.array([len(boys), len(girls)])
    
    stat, pvalue = proportions_ztest(count, nobs)
    low, high = confint_proportions_2indep(count[0], nobs[0], count[1], nobs[1])
    print(f"difference {boys.mean() - girls.mean():+.1%}")
    print(f"95% CI [{low:+.1%}, {high:+.1%}]")
    print(f"z = {stat:.2f}, p = {pvalue:.3f}")
    Notes du présentateur
    Les deux intervalles se recouvrent. Un recouvrement d'intervalles est un indice et non un test — ce qu'il faut calculer, c'est un intervalle sur la différence.
  6. Diapositive 6 / 25

    Écart numéro un : celui qui n'y est pas — En R

    prop.test(c(200, 183), c(510, 542))
  7. Diapositive 7 / 25

    Écart numéro un : celui qui n'y est pas

    • Différence +5,5 points, IC à 95 % −0,4 à +11,3, p = 0,066
    Notes du présentateur
    Différence +5,5 points, IC à 95 % −0,4 à +11,3, p = 0,066. L'intervalle contient zéro. La réponse honnête n'est donc pas « il n'y a pas d'écart » — c'est « cette enquête ne peut pas vous dire s'il y a un écart, et s'il y en a un il se situe quelque part entre des filles légèrement plus mal loties et des garçons plus mal lotis de onze points ». C'est une phrase réellement utile et ce n'est pas la même chose qu'un résultat nul.
  8. Diapositive 8 / 25

    Écart numéro deux : celui qui y est — En Python

    protection = pd.read_csv("protection-referrals-2024.v1.csv")
    consenting = protection[protection["consent_to_refer"]]
    reached = (consenting["referral_accepted"]
               & consenting["days_to_first_service"].notna())
    
    disability = consenting["disability_reported"].isin([True, "true", "Yes"])
    k = np.array([reached[disability].sum(), reached[~disability].sum()])
    n = np.array([disability.sum(), (~disability).sum()])
    
    stat, pvalue = proportions_ztest(k, n)
    low, high = confint_proportions_2indep(k[0], n[0], k[1], n[1])
    print(f"{k[0]}/{n[0]} = {k[0]/n[0]:.1%}   {k[1]}/{n[1]} = {k[1]/n[1]:.1%}")
    print(f"difference {k[0]/n[0] - k[1]/n[1]:+.1%}, CI [{low:+.1%}, {high:+.1%}]")
    print(f"z = {stat:.2f}, p = {pvalue:.2e}")
  9. Diapositive 9 / 25

    Écart numéro deux : celui qui y est — En R

    prop.test(c(54, 663), c(202, 1436))
  10. Diapositive 10 / 25

    Écart numéro deux : celui qui y est

    GroupeAboutissementn
    Handicap signalé26,7 %202
    Non signalé46,2 %1 436
  11. Diapositive 11 / 25

    Écart numéro deux : celui qui y est

    • Différence −19,4 points, IC à 95 % −26,1 à −12,8, p < 0,001
    • Toute valeur de cet intervalle est un écart substantiel — Le plus petit écart compatible avec les données vaut 12,8…
    Notes du présentateur
    Différence −19,4 points, IC à 95 % −26,1 à −12,8, p < 0,001. Toute valeur de cet intervalle est un écart substantiel. Le plus petit écart compatible avec les données vaut 12,8 points, ce qui reste assez grand pour agir. C'est ce qui en fait un constat plutôt qu'un indice.
  12. Diapositive 12 / 25

    Les deux résultats côte à côte — En Python

    results = pd.DataFrame([
        {"comparison": "over-age, boys vs girls", "diff": 5.5,
         "ci": "-0.4 to +11.3", "n": "510 vs 542", "p": 0.066},
        {"comparison": "completion, disability", "diff": -19.4,
         "ci": "-26.1 to -12.8", "n": "202 vs 1436", "p": 0.0000002},
    ])
    print(results)
  13. Diapositive 13 / 25

    Les deux résultats côte à côte — En R

    # Two rows. The conclusion column is the analyst's, not the test's.
  14. Diapositive 14 / 25

    Les deux résultats côte à côte

    • Remarquez que le résultat significatif a le plus petit échantillon dans l'un des bras — 202 cas ont produit une réponse…
    Notes du présentateur
    Remarquez que le résultat significatif a le plus petit échantillon dans l'un des bras. 202 cas ont produit une réponse tranchée et 510 élèves non, parce que la taille d'effet est presque quatre fois plus grande. Taille d'échantillon et taille d'effet s'échangent, et c'est leur combinaison qui décide si une comparaison se tranche.
  15. Diapositive 15 / 25

    Choisir le test

    ComparaisonTestDans ce cours
    Deux proportionsTest z à deux échantillons, ou prop.testLes deux écarts ci-dessus
    Deux moyennesTest t de WelchPrésence et cantine, leçon 6
    Une variable catégorielle contre une autreKhi-deuxMotif de fermeture par district
    Notes du présentateur
    Trois tests couvrent presque tout ce qu'un rapport de programme compare, et le choix se fait d'après la nature du résultat plutôt que d'après ce qui paraît sophistiqué.
  16. Diapositive 16 / 25

    Choisir le test — En Python

    from scipy import stats
    
    points = pd.read_csv("water-point-monitoring-2024.v1.csv")
    table = pd.crosstab(points["admin2"], points["functional_status"])
    chi2, p, dof, expected = stats.chi2_contingency(table)
    print(f"chi-square {chi2:.1f}, dof {dof}, p = {p:.4f}")
    print(f"smallest expected cell: {expected.min():.1f}")
  17. Diapositive 17 / 25

    Choisir le test — En R

    chisq.test(table(points$admin2, points$functional_status))
  18. Diapositive 18 / 25

    Vérifiez les hypothèses, et dites que vous l'avez fait

    • Indépendance — Tous les tests ci-dessus supposent que chaque ligne est une observation indépendante
    • Effectifs attendus pour le khi-deux — Le test devient peu fiable quand une cellule attendue passe sous cinq environ
    • Égalité des variances pour le test t — Ne la vérifiez pas — employez toujours le test t de Welch, qui ne la suppose pas
    Notes du présentateur
    Chaque test suppose des choses, et deux d'entre elles se vérifient en une ligne. Indépendance. Tous les tests ci-dessus supposent que chaque ligne est une observation indépendante. C'est l'hypothèse la plus souvent violée et la plus difficile à voir — la leçon 6 porte entièrement sur un cas où elle tombe. Effectifs attendus pour le khi-deux. Le test devient peu fiable quand une cellule attendue passe sous cinq environ. Affichez expected.min() à chaque fois ; s'il est petit, regroupez des catégories ou employez le test exact de Fisher. Égalité des variances pour le test t. Ne la vérifiez pas — employez toujours le test t de Welch, qui ne la suppose pas. scipy.stats.ttest_ind(..., equal_var=False) et le comportement par défaut de t.test en R. La version qui suppose des variances égales n'apporte rien et tombe dès que les groupes diffèrent par leur dispersion.
  19. Diapositive 19 / 25

    Vérifiez les hypothèses, et dites que vous l'avez fait — En Python

    girls_rate, boys_rate = girls.mean(), boys.mean()
    print("assumptions checked:")
    print(f"  independence: one row per student, no student in two rows — verified")
    print(f"  sample sizes: {len(boys)} and {len(girls)}, both well above 30")
    print(f"  expected counts: smallest is {min(len(boys), len(girls)) * min(girls_rate, 1 - boys_rate):.0f}")
  20. Diapositive 20 / 25

    Vérifiez les hypothèses, et dites que vous l'avez fait — En R

    # Write the check into the script, not into your memory of having done it.
  21. Diapositive 21 / 25

    Rapportez la différence, non les deux nombres — Exemple (suite)

    Over-age enrolment by sex, primary, 2024
    
      Boys    39.2%   n = 510
      Girls   33.8%   n = 542
      Difference +5.5 points, 95% CI -0.4 to +11.3, p = 0.066
    
      The interval includes zero. This survey cannot establish whether over-age
      enrolment differs by sex; if it does, the gap is between 0 and 11 points
      and boys are the disadvantaged group. Not reported as a finding.
    
    Referral completion by disability status, 1,638 consenting cases
    
      Disability reported     26.7%   n = 202
      Not reported            46.2%   n = 1,436
      Difference -19.4 points, 95% CI -26.1 to -12.8, p < 0.001
    
  22. Diapositive 22 / 25

    Rapportez la différence, non les deux nombres — Exemple (suite)

      The smallest gap consistent with the data is 12.8 points. Reported as a
      finding, and the pathway lesson locates it at referral-making and
      acceptance rather than at consent.
  23. Diapositive 23 / 25

    Rapportez la différence, non les deux nombres

    • Les deux blocs mettent la différence et son intervalle en titre — avec les deux valeurs de groupe en dessous
    Notes du présentateur
    Les deux blocs mettent la différence et son intervalle en titre, avec les deux valeurs de groupe en dessous. Cet ordre est délibéré : la différence est l'affirmation, et les deux proportions en sont la preuve.
  24. Diapositive 24 / 25

    La suite

    • L'un de ces écarts est statistiquement significatif.
    Notes du présentateur
    L'un de ces écarts est statistiquement significatif. La leçon suivante demande si c'est la même chose qu'être important — et trouve une comparaison où un p inférieur à 0,001 décrit une différence sur laquelle aucun programme n'agirait.
  25. Diapositive 25 / 25

    La suite

    Lire la leçon complète, avec le code exécutable Retour à la leçon