cassionAnalyse de données

Retour à la leçonLeçon 8 sur 8Produire une réponse

Faire en sorte que cela tourne encore au trimestre suivant

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

    Ce que couvre cette leçon

    • Le test
    • Découpez l'analyse en étapes qui se passent des fichiers
    • Rassemblez les paramètres en un seul endroit
    • Faites échouer la chaîne bruyamment
    • Paramétrez au lieu de copier
    • Ce qui ne va jamais dans le dépôt
    • Le README de passation
    • Pour aller plus loin
    Notes du présentateur
    Transformer une analyse qui fonctionne en une analyse qui se relance sur un nouvel export sans modification, échoue bruyamment quand l'entrée change, et se transmet à quelqu'un qui n'a rien de votre contexte.
  2. Diapositive 2 / 21

    Le test

    • L'export du trimestre suivant arrive.
    Notes du présentateur
    L'export du trimestre suivant arrive. Combien d'éléments devez-vous modifier avant que le rapport ne se régénère ? Si la réponse dépasse un — le chemin du fichier d'entrée — l'analyse n'est pas reproductible : c'est le compte rendu d'un après-midi. Cette leçon ramène la réponse à un.
  3. Diapositive 3 / 21

    Découpez l'analyse en étapes qui se passent des fichiers — Exemple

    scripts/
      01-lecture.py      export brut  -> data/interim/muac-type.parquet
      02-nettoyage.py    typé         -> data/processed/muac-propre.parquet
                                         output/tables/journal-nettoyage.csv
      03-indicateurs.py  propre       -> output/tables/mag-par-commune.csv
    Notes du présentateur
    Trois scripts, chacun avec une seule mission, chacun écrivant un fichier que le suivant lit.
  4. Diapositive 4 / 21

    Découpez l'analyse en étapes qui se passent des fichiers — En Python

    muac.to_parquet("data/interim/muac-type.parquet", index=False)
    Notes du présentateur
    L'intérêt n'est pas le rangement. C'est que, lorsque le tableau d'indicateurs paraît faux, vous puissiez relancer la troisième étape en deux secondes au lieu de réexécuter un notebook de quinze minutes, et qu'un collègue qui débogue la deuxième n'ait pas à comprendre la troisième. Utilisez Parquet plutôt que CSV entre les étapes. Ce format préserve les types — autrement dit, le travail fait en leçon 3 pour que child_id soit lu comme du texte n'est pas défait à la première écriture-relecture.
  5. Diapositive 5 / 21

    Découpez l'analyse en étapes qui se passent des fichiers — En R

    arrow::write_parquet(muac, "data/interim/muac-type.parquet")
  6. Diapositive 6 / 21

    Rassemblez les paramètres en un seul endroit — En Python

    # config.py
    from pathlib import Path
    
    BRUT = Path("data/raw/muac-screening-artibonite-2024.v1.csv")
    INTERMEDIAIRE = Path("data/interim/muac-type.parquet")
    TRAITE = Path("data/processed/muac-propre.parquet")
    TABLEAUX = Path("output/tables")
    
    MAS_MM = 115
    MAG_MM = 125
    PB_PLAUSIBLE = (80, 220)
    AGE_MOIS = (6, 59)
    CODE_MANQUANT = "-99"
    Notes du présentateur
    Chaque seuil, chemin et valeur de coupure figure en tête de fichier ou dans une configuration, jamais enfoui au milieu d'une expression.
  7. Diapositive 7 / 21

    Rassemblez les paramètres en un seul endroit — En R

    # config.R
    BRUT          <- "data/raw/muac-screening-artibonite-2024.v1.csv"
    INTERMEDIAIRE <- "data/interim/muac-type.parquet"
    TRAITE        <- "data/processed/muac-propre.parquet"
    TABLEAUX      <- "output/tables"
    
    MAS_MM        <- 115
    MAG_MM        <- 125
    PB_PLAUSIBLE  <- c(80, 220)
    AGE_MOIS      <- c(6, 59)
    CODE_MANQUANT <- "-99"
    Notes du présentateur
    Un relecteur qui veut connaître les seuils employés lit un seul fichier. Un successeur qui adapte ce travail à un autre pays modifie un seul fichier. Et quand l'OMS révise une valeur de coupure, vous changez un nombre au lieu de chercher 125 dans quatre scripts en manquant celui qui s'écrit 12.5 * 10.
  8. Diapositive 8 / 21

    Faites échouer la chaîne bruyamment — En Python (suite)

    def controler_entree(df):
        attendues = {
            "child_id", "commune", "screening_date", "age_months",
            "sex", "muac_mm", "oedema", "outcome",
        }
        absentes = attendues - set(df.columns)
        if absentes:
            raise ValueError(f"colonnes absentes de l'export : {sorted(absentes)}")
    
        if df["child_id"].isna().any():
            raise ValueError("lignes sans identifiant")
    
        mesures = df["muac_mm"].dropna()
        if len(mesures) == 0:
            raise ValueError("aucune mesure de PB — mauvais fichier ?")
    
    Notes du présentateur
    Une analyse qui produit silencieusement un chiffre faux est pire qu'une analyse qui plante. Affirmez ce qui doit être vrai, à chaque frontière d'étape.
  9. Diapositive 9 / 21

    Faites échouer la chaîne bruyamment — En Python (suite)

        part_manquante = df["muac_mm"].isna().mean()
        if part_manquante > 0.20:
            raise ValueError(
                f"{part_manquante:.1%} de PB manquants — au-dessus de la tolérance de 20 %. "
                "À investiguer avant tout rapportage."
            )
  10. Diapositive 10 / 21

    Faites échouer la chaîne bruyamment — En R (suite)

    controler_entree <- function(df) {
      attendues <- c("child_id", "commune", "screening_date", "age_months",
                     "sex", "muac_mm", "oedema", "outcome")
      absentes <- setdiff(attendues, names(df))
      if (length(absentes) > 0) {
        stop("colonnes absentes de l'export : ", paste(absentes, collapse = ", "))
      }
    
      if (any(is.na(df$child_id))) stop("lignes sans identifiant")
    
      part_manquante <- mean(is.na(df$muac_mm))
      if (part_manquante > 0.20) {
        stop(sprintf(
          "%.1f%% de PB manquants - au-dessus de la tolerance de 20%%. A investiguer avant tout rapportage.",
          part_manquante * 100
        ))
  11. Diapositive 11 / 21

    Faites échouer la chaîne bruyamment — En R (suite)

      }
    }
  12. Diapositive 12 / 21

    Faites échouer la chaîne bruyamment

    Écrivez l'assertion correspondant à la défaillance qui vous embarrasserait, pas à celle que vous jugez probable. Les probables, vous les remarquerez.
    Notes du présentateur
    Le contrôle de seuil est le plus intéressant. Il encode un jugement éditorial — au-delà de 20 % de manquants, le taux ne mérite pas d'être publié — et l'applique automatiquement à chaque export futur, y compris à ceux traités par quelqu'un qui n'a jamais lu cette leçon.
  13. Diapositive 13 / 21

    Paramétrez au lieu de copier — En Python (suite)

    import sys
    from pathlib import Path
    
    def produire_rapport(commune: str | None = None):
        df = pd.read_parquet(TRAITE)
        if commune:
            df = df[df["commune"] == commune]
            if df.empty:
                raise ValueError(f"aucune ligne pour la commune {commune!r}")
    
        tableau = tableau_indicateurs(df, "tranche_age")
        nom = commune.lower().replace(" ", "-") if commune else "toutes"
        tableau.to_csv(TABLEAUX / f"mag-{nom}.csv", index=False)
        return tableau
    
    
    Notes du présentateur
    Douze communes, douze rapports communaux. Ne copiez pas le script douze fois.
  14. Diapositive 14 / 21

    Paramétrez au lieu de copier — En Python (suite)

    if __name__ == "__main__":
        cible = sys.argv[1] if len(sys.argv) > 1 else None
        produire_rapport(cible)
  15. Diapositive 15 / 21

    Paramétrez au lieu de copier — En R

    produire_rapport <- function(commune = NULL) {
      df <- arrow::read_parquet(TRAITE)
      if (!is.null(commune)) {
        df <- filter(df, commune == !!commune)
        if (nrow(df) == 0) stop("aucune ligne pour la commune ", commune)
      }
    
      tableau <- tableau_indicateurs(df, "tranche_age")
      nom <- if (is.null(commune)) "toutes" else tolower(gsub(" ", "-", commune))
      readr::write_csv(tableau, file.path(TABLEAUX, paste0("mag-", nom, ".csv")))
      tableau
    }
    
    args <- commandArgs(trailingOnly = TRUE)
    produire_rapport(if (length(args) > 0) args[1] else NULL)
    Notes du présentateur
    Le même schéma s'étend au rapport narratif complet. Quarto compose un modèle unique avec un paramètre, douze fois, produisant douze documents qui ne peuvent pas diverger puisqu'il n'existe qu'un seul document.
  16. Diapositive 16 / 21

    Ce qui ne va jamais dans le dépôt

    • Ne versionnez jamais de données brutes de bénéficiaires. Ni identifiées, ni pseudonymisées. Git conserve chaque…
    • Ne versionnez jamais d'identifiants de connexion. Jetons DHIS2, clés d'API KoboToolbox, mots de passe de base de…
    • Ajoutez data/raw/ au .gitignore et documentez dans le README où se trouve le vrai fichier — un disque partagé,…
    Notes du présentateur
    Ce point compte davantage dans ce secteur qu'ailleurs. Un dépôt contenant des données de programme peut contenir des noms de bénéficiaires, des points GPS qui identifient un ménage, ou une liste de cas de protection.
  17. Diapositive 17 / 21

    Ce qui ne va jamais dans le dépôt — Exemple

    data/raw/
    data/interim/
    data/processed/
    .env
    *.Rhistory
    __pycache__/
    .Rproj.user/
    Notes du présentateur
    Le code d'analyse est ce qui a sa place sous gestion de versions. Les données ont la leur là où la politique de protection des données de votre organisation le prescrit, et le README doit indiquer où.
  18. Diapositive 18 / 21

    Le README de passation — Exemple (suite)

    # Analyse du dépistage PB, Artibonite
    
    ## Ce que cela produit
    Taux trimestriels de MAG et de MAS par commune, sexe et tranche d'âge, avec
    intervalles à 95 %. Alimente la décision d'implantation des sites PCIMA et le
    rapport bailleur trimestriel.
    
    ## D'où viennent les données
    Export CommCare, projet `artibonite-nutrition`, formulaire `Dépistage
    communautaire`. Exporté chaque mois par l'assistant suivi-évaluation vers le
    disque partagé à <chemin>. Absent de ce dépôt.
    
    ## Comment l'exécuter
        uv sync
        uv run python scripts/01-lecture.py
        uv run python scripts/02-nettoyage.py
    Notes du présentateur
    Rédigé pour quelqu'un qui aura votre intitulé de poste et rien de votre contexte. Cinq rubriques.
  19. Diapositive 19 / 21

    Le README de passation — Exemple (suite)

        uv run python scripts/03-indicateurs.py
    
    ## Décisions à connaître
    Voir output/tables/journal-nettoyage.csv. Celle qui compte : les lignes sans
    âge sont conservées, car 60 % de la semaine du 10 au 14 juin à Gros-Morne est
    sans âge et leur suppression modifie le classement des communes.
    
    ## Qui contacter
    Définitions d'indicateurs : <nom>, responsable suivi-évaluation.
    Problèmes de collecte : <nom>, coordinateur terrain.
    Notes du présentateur
    Ce README fait la différence entre un successeur qui poursuit votre travail et un successeur qui le reconstruit sur tableur faute d'avoir pu deviner ce que vos scripts supposaient.
  20. Diapositive 20 / 21

    Pour aller plus loin

    • Nettoyage et validation des données approfondit le profilage et les corrections des leçons 5 et 6, avec…
    • Conception d'indicateurs et cadre logique part de la fiche de référence de la leçon 7 et remonte jusqu'à la théorie…
    • Analyse d'enquêtes, échantillonnage et pondération couvre ce que cette formation n'a pas abordé : ce qui change…
    Notes du présentateur
    Vous savez désormais mener un export de programme de son arrivée à un tableau d'indicateurs défendable, dans l'un ou l'autre langage, avec le raisonnement consigné. C'est le socle sur lequel s'appuie le reste du programme : Entraînez-vous sur un autre jeu de données avant de poursuivre. L'enquête ménage EAH et le registre de couverture vaccinale de routine de cette plateforme portent un tout autre assortiment de défauts, et en traiter un de bout en bout sans la leçon sous les yeux est le véritable test de ce qui est resté.
  21. Diapositive 21 / 21

    La suite

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