cassionAnalyse de données

Retour à la leçonLeçon 7 sur 8Juger un programme

Le dénominateur qui déplace le taux de guérison de neuf points

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 / 26

    Ce que couvre cette leçon

    • Quatre issues et un standard
    • Les trois dénominateurs candidats
    • Celui que Sphere désigne
    • Décomposez par site
    • La cause est en général la distance, non l'observance
    • Le gain de poids, et les saisies qui ne peuvent pas être justes
    • Le tableau de performance à publier
    • La suite
    Notes du présentateur
    Guéris, abandons, décès, non-réponse — au regard des standards minimums Sphere, sur le dénominateur que Sphere spécifie réellement. 82,3 % ou 73,6 %, selon un choix que personne ne documente, et un site hors standard que le chiffre du district masque.
  2. Diapositive 2 / 26

    Quatre issues et un standard

    IssueMinimum Sphere, soins thérapeutiques ambulatoires
    Guérisplus de 75 %
    Décèsmoins de 10 %
    Abandonsmoins de 15 %
    Non-réponsepas de seuil fixe ; investiguée si élevée
    Notes du présentateur
    Un programme PCIMA est jugé sur ce qu'il est advenu des enfants qu'il a admis, et les standards minimums Sphere donnent les seuils.
  3. Diapositive 3 / 26

    Quatre issues et un standard

    • Chacun est une proportion, et la discussion porte toujours sur le dénominateur
    Notes du présentateur
    L'alimentation supplémentaire a son propre jeu — guéris au-dessus de 75 %, décès sous 3 %, abandons sous 15 %. Les nombres diffèrent ; la structure non. Chacun est une proportion, et la discussion porte toujours sur le dénominateur.
  4. Diapositive 4 / 26

    Les trois dénominateurs candidats — En Python

    import pandas as pd
    
    cmam = pd.read_csv("cmam-admissions-2024.v1.csv")
    
    print(f"admissions:            {len(cmam):>5}")
    print(f"with an outcome:       {cmam['outcome'].notna().sum():>5}")
    print(f"excluding transfers:   "
          f"{(cmam['outcome'].notna() & (cmam['outcome'] != 'transferred')).sum():>5}")
  5. Diapositive 5 / 26

    Les trois dénominateurs candidats — En R

    cmam |> summarise(
      admissions = n(),
      with_outcome = sum(!is.na(outcome)),
      excluding_transfers = sum(!is.na(outcome) & outcome != "transferred")
    )
  6. Diapositive 6 / 26

    Les trois dénominateurs candidats

    DénominateurnCe qu'il fait des exclus
    Toutes les admissions1 100Les enfants encore en traitement comptés comme non guéris
    Ayant atteint une issue1 029Les transferts comptés comme une issue
    Ayant atteint une issue, transferts exclus984—
  7. Diapositive 7 / 26

    Les trois dénominateurs candidats — En Python

    cured = (cmam["outcome"] == "cured").sum()
    for label, n in [("all admissions", 1100), ("with an outcome", 1029),
                     ("excluding transfers", 984)]:
        print(f"cure rate on {label:22} {cured / n:.1%}")
  8. Diapositive 8 / 26

    Les trois dénominateurs candidats — En R

    cured <- sum(cmam$outcome == "cured", na.rm = TRUE)
    c(all = cured / 1100, outcome = cured / 1029, sphere = cured / 984)
  9. Diapositive 9 / 26

    Les trois dénominateurs candidats

    • 73,6 %, 78,7 %, 82,3 % — Un numérateur, trois dénominateurs, neuf points
    Notes du présentateur
    73,6 %, 78,7 %, 82,3 %. Un numérateur, trois dénominateurs, neuf points. Et l'un d'eux franchit un seuil : sur toutes les admissions le programme est sous le minimum Sphere de 75 % et sur le dénominateur Sphere il est confortablement au-dessus. La différence n'est pas la performance. C'est un dénominateur que personne n'a écrit.
  10. Diapositive 10 / 26

    Celui que Sphere désigne

    • Les enfants ayant atteint une issue thérapeutique, transferts exclus — 984 ici
    • Les enfants encore en traitement ne sont pas une issue — Soixante et onze enfants ont été admis assez tard pour ne pas…
    • Les transferts sont l'issue de quelqu'un d'autre — Quarante-cinq enfants sont passés d'un programme à l'autre —…
    Notes du présentateur
    Les enfants ayant atteint une issue thérapeutique, transferts exclus. 984 ici. Les deux exclusions ont des motifs différents et les deux sont justes. Les enfants encore en traitement ne sont pas une issue. Soixante et onze enfants ont été admis assez tard pour ne pas être sortis à la date d'arrêt. Ils ne sont ni guéris ni abandons ; ils sont en traitement. Les compter dans une catégorie quelconque est une affirmation sur un avenir qui n'a pas eu lieu. Les transferts sont l'issue de quelqu'un d'autre. Quarante-cinq enfants sont passés d'un programme à l'autre — ambulatoire vers hospitalier, ou l'inverse — et leur issue thérapeutique sera enregistrée là où ils aboutissent. Les compter ici reviendrait à les compter deux fois entre les deux programmes, ou à créditer ce programme d'un résultat qu'il n'a pas produit.
  11. Diapositive 11 / 26

    Celui que Sphere désigne — En Python

    performance = cmam[cmam["outcome"].notna() & (cmam["outcome"] != "transferred")]
    
    rates = performance["outcome"].value_counts(normalize=True)
    print((rates * 100).round(1))
    print(f"n = {len(performance)}")
  12. Diapositive 12 / 26

    Celui que Sphere désigne — En R

    performance <- cmam |> filter(!is.na(outcome), outcome != "transferred")
    
    performance |> count(outcome) |> mutate(rate = n / sum(n))
  13. Diapositive 13 / 26

    Celui que Sphere désigne

    IssueTauxSphere
    Guéris82,3 %plus de 75 %passe
    Abandons13,7 %moins de 15 %passe
    Décès1,0 %moins de 10 %passe
    Non-réponse2,9 %—
    Notes du présentateur
    Quatre lignes, toutes dans le standard. C'est là que s'arrêtent la plupart des rapports PCIMA, et c'est là que le constat se cache.
  14. Diapositive 14 / 26

    Décomposez par site — En Python

    by_site = (
        performance.assign(**{o: performance["outcome"] == o
                              for o in ["cured", "defaulted", "died", "non-response"]})
        .groupby("site_id")
        .agg(n=("outcome", "size"), cured=("cured", "mean"),
             defaulted=("defaulted", "mean"), died=("died", "mean"))
    )
    print((by_site[["cured", "defaulted", "died"]] * 100).round(1))
  15. Diapositive 15 / 26

    Décomposez par site — En R

    performance |>
      summarise(n = n(),
                cured = mean(outcome == "cured"),
                defaulted = mean(outcome == "defaulted"),
                died = mean(outcome == "died"),
                .by = site_id) |>
      arrange(desc(defaulted))
  16. Diapositive 16 / 26

    Décomposez par site

    SitenAbandons
    SITE-0315620,5 %
    SITE-0216815,5 %
    SITE-0612513,6 %
    SITE-0514211,3 %
    SITE-0118811,2 %
    SITE-0420511,2 %
  17. Diapositive 17 / 26

    Décomposez par site

    • Le programme abandonne à 13,7 % et un site à 20,5 % — Le chiffre du district est sous le maximum Sphere et ce site ne…
    Notes du présentateur
    Le programme abandonne à 13,7 % et un site à 20,5 %. Le chiffre du district est sous le maximum Sphere et ce site ne l'est pas, de cinq points. C'est toute la raison pour laquelle le cours d'évaluation insistait sur les distributions plutôt que sur les moyennes, et cela arrive ici avec une conséquence clinique — un enfant qui abandonne est un enfant qui a cessé le traitement avant guérison.
  18. Diapositive 18 / 26

    Décomposez par site — En Python

    flagged = by_site[(by_site["defaulted"] > 0.15) | (by_site["cured"] < 0.75)]
    print(f"{len(flagged)} of {len(by_site)} sites outside a Sphere standard")
  19. Diapositive 19 / 26

    Décomposez par site — En R

    performance |>
      summarise(cured = mean(outcome == "cured"),
                defaulted = mean(outcome == "defaulted"), .by = site_id) |>
      filter(defaulted > 0.15 | cured < 0.75)
    Notes du présentateur
    Deux sites, et le second est limite à 15,5 %. Signalez par rapport au standard, non par rapport à la moyenne du district — c'est au standard que le programme est tenu.
  20. Diapositive 20 / 26

    La cause est en général la distance, non l'observance — En Python

    length_of_stay = (
        pd.to_datetime(performance["discharge_date"])
        - pd.to_datetime(performance["admission_date"])
    ).dt.days
    
    print(performance.assign(stay=length_of_stay)
          .groupby("outcome")["stay"].median().round(0))
    Notes du présentateur
    L'abandon a une littérature et elle est constante : le meilleur prédicteur est le temps de trajet jusqu'au site. Un accompagnant qui doit perdre une journée de travail chaque semaine pour marcher deux heures cessera de venir quand l'enfant aura meilleure mine, ce qui est rationnel et n'est pas de l'inobservance.
  21. Diapositive 21 / 26

    La cause est en général la distance, non l'observance — En R

    performance |>
      mutate(stay = as.integer(as.Date(discharge_date) - as.Date(admission_date))) |>
      summarise(median_stay = median(stay), .by = outcome)
    Notes du présentateur
    Les abandons partent bien plus tôt que les enfants guéris — le séjour médian est d'environ trois semaines contre environ huit. Un abandon n'est pas un échec thérapeutique, c'est un enfant parti avant la fin du traitement, et l'action corrective est la décentralisation ou un appui au transport, non du counseling. C'est la discipline de cause racine du cours d'évaluation, appliquée à un indicateur clinique.
  22. Diapositive 22 / 26

    Le gain de poids, et les saisies qui ne peuvent pas être justes — En Python

    gain = (
        (performance["weight_discharge_kg"] - performance["weight_admission_kg"])
        / performance["weight_admission_kg"]
        / length_of_stay * 1000
    )
    print(gain.describe().round(1))
    print(f"{(gain < 0).sum()} discharges with weight loss")
  23. Diapositive 23 / 26

    Le gain de poids, et les saisies qui ne peuvent pas être justes — En R

    performance |>
      mutate(gain = (weight_discharge_kg - weight_admission_kg) /
                    weight_admission_kg / as.integer(as.Date(discharge_date) -
                    as.Date(admission_date)) * 1000) |>
      summarise(median = median(gain, na.rm = TRUE), negative = sum(gain < 0, na.rm = TRUE))
    Notes du présentateur
    Le gain de poids en grammes par kilogramme et par jour est la mesure classique de la réponse au traitement, et neuf sorties présentent une perte de poids. C'est possible chez un enfant décédé ou ayant abandonné tôt, et c'est aussi exactement l'allure d'une saisie inversée. Le registre ne permet pas de les distinguer, ce qui est un constat pour la section qualité des données plutôt qu'un nombre à nettoyer.
  24. Diapositive 24 / 26

    Le tableau de performance à publier — Exemple

    CMAM performance, 2024
    
      Admissions                        1,100
      Still in treatment at cut-off        71    excluded: not an outcome
      Transferred                          45    excluded: outcome recorded elsewhere
      Performance denominator             984
    
      Cured           82.3%   Sphere >75%    pass
      Defaulted       13.7%   Sphere <15%    pass
      Died             1.0%   Sphere <10%    pass
      Non-response     2.9%
    
      One site (SITE-03, n=156) defaults at 20.5%, outside the Sphere maximum.
      Median stay for defaulters is 24 days against 58 for cured children,
      consistent with distance rather than non-response to treatment.
    Notes du présentateur
    Les lignes exclues sont montrées, non supprimées. Un lecteur peut reconstituer n'importe lequel des trois dénominateurs à partir de ce bloc, ce qui fait la différence entre un tableau de performance et une affirmation.
  25. Diapositive 25 / 26

    La suite

    • Le programme guérit les enfants qu'il admet.
    Notes du présentateur
    Le programme guérit les enfants qu'il admet. La dernière leçon pose la question plus difficile — quelle part des enfants ayant besoin d'un traitement il a jamais vue — et pourquoi le chiffre que la plupart des programmes rapportent comme couverture n'en est pas une.
  26. Diapositive 26 / 26

    La suite

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