cassionAnalyse de données

Leçon 2 sur 8

Unité · Un environnement qui tiendra

Un projet qu'une autre personne peut ouvrir

Où vivent les données brutes, le code et les sorties, pourquoi un chemin en dur garantit que le script ne tourne que sur une machine, et la règle qui rend une analyse rejouable — ne jamais écrire dans le dossier que l'on lit.

Python70 min

La forme d’un projet

Presque toute analyse de ce secteur comporte les quatre mêmes sortes de fichiers, et donner à chacune un emplacement fixe supprime une catégorie de questions que personne ne devrait avoir à poser.

muac-analysis/
  data/
    raw/            l'export tel qu'il est arrive, jamais modifie
    interim/        fichiers intermediaires, supprimables sans risque
  outputs/
    tables/
    figures/
  scripts/
    read_register.py
    indicator_table.py
  notebooks/
    exploration.ipynb
  pyproject.toml
  uv.lock
  README.md
  .gitignore

La ligne importante est la première.

data/raw est en lecture seule

L’export tel qu’il est arrivé est la seule chose du projet que vous ne pouvez pas reproduire. Tout le reste — le tableau nettoyé, les figures, les tableaux d’indicateurs — peut être régénéré en réexécutant le code. Le fichier brut, non : le serveur d’où il vient aura changé.

Il n’est donc jamais modifié, jamais écrasé, jamais trié dans Excel « juste pour regarder ». Si une correction arrive, elle se pose à côté de l’original sous un nouveau nom plutôt que de le remplacer.

Ce nommage mérite d’être délibéré :

data/raw/muac-screening-artibonite-2024.v1.csv
data/raw/muac-screening-artibonite-2024.v2.csv

et non

data/raw/muac_final.csv
data/raw/muac_final_v2.csv
data/raw/muac_FINAL_corrige(1).csv

Une analyse exécutée sur la v1 doit continuer à se reproduire sur la v1. Si le nom de fichier est écrasé, le chiffre du trimestre dernier ne pourra plus jamais être expliqué — et expliquer le chiffre du trimestre dernier fait partie de ce qu’on vous demandera.

Des chemins qui fonctionnent sur la machine d’un autre

C’est la raison la plus fréquente pour laquelle le script d’un collègue échoue sur votre portable :

# S'execute sur exactement un ordinateur.
muac = pd.read_csv("C:/Users/marie/Bureau/muac-screening-artibonite-2024.v1.csv")

Le correctif consiste à écrire des chemins relatifs au projet, et à laisser Python déterminer où se trouve le projet.

from pathlib import Path
import pandas as pd

# __file__ est ce script ; son parent est scripts/, dont le parent est le projet.
PROJECT = Path(__file__).resolve().parent.parent
RAW = PROJECT / "data" / "raw"
OUTPUTS = PROJECT / "outputs"

muac = pd.read_csv(RAW / "muac-screening-artibonite-2024.v1.csv")

Trois avantages :

  • Il s’exécute depuis n’importe où. python scripts/indicator_table.py et python /home/marie/muac-analysis/scripts/indicator_table.py fonctionnent tous deux, car les chemins sont calculés à partir de l’emplacement du script lui-même et non du répertoire courant du terminal.
  • Il fonctionne sous Windows. Path assemble avec / dans votre source et produit \ sous Windows. Ne construisez jamais un chemin par concaténation de chaînes.
  • Il est repérable. Chaque fichier touché par le script se trouve sous RAW ou OUTPUTS : un lecteur voit les entrées et les sorties d’un coup d’œil.

Dans un notebook, __file__ n’existe pas. Définissez plutôt la racine du projet explicitement dans la première cellule, et gardez le reste du notebook relatif à elle :

from pathlib import Path

PROJECT = Path.cwd().parent      # le notebook vit dans notebooks/
assert (PROJECT / "data" / "raw").exists(), f"pas la racine du projet : {PROJECT}"

L’assertion compte plus qu’il n’y paraît. Sans elle, un notebook lancé depuis le mauvais répertoire échoue plusieurs cellules plus loin, sur une erreur déroutante concernant une colonne absente.

Les sorties sont jetables, et c’est le test

Si supprimer outputs/ puis réexécuter les scripts ne le restaure pas à l’identique, quelque chose dans l’analyse n’est pas reproductible — une étape manuelle, une modification faite dans Excel, une cellule exécutée dans le désordre.

rm -rf outputs/
uv run python scripts/indicator_table.py
git status                      # ne doit rien afficher d'inattendu

Prenez-en l’habitude avant toute transmission. C’est la vérification la moins coûteuse qui soit et elle attrape la défaillance la plus difficile à diagnostiquer plus tard.

Créez les répertoires de sortie depuis le code plutôt que d’attendre qu’ils existent :

OUTPUTS = PROJECT / "outputs" / "tables"
OUTPUTS.mkdir(parents=True, exist_ok=True)

indicator_table.to_csv(OUTPUTS / "gam_by_commune.csv", index=False)

parents=True crée les répertoires intermédiaires ; exist_ok=True fait qu’une seconde exécution n’échoue pas. Un collègue qui clone le projet obtient les dossiers sans qu’on le lui dise.

Ce qui entre dans le contrôle de version

À versionner À ne pas versionner
scripts/, notebooks/ data/raw/ — voir ci-dessous
pyproject.toml, uv.lock data/interim/
README.md outputs/
.gitignore .venv/, __pycache__/
.venv/
__pycache__/
*.pyc
data/raw/
data/interim/
outputs/
.ipynb_checkpoints/

Ne versionnez jamais de données brutes de bénéficiaires, identifiées ou pseudonymisées. Git conserve chaque version de chaque fichier pour toujours ; un fichier supprimé dans un commit ultérieur reste dans l’historique, et un dépôt interne le lundi peut être partagé le vendredi. Si les données sont synthétiques ou déjà publiques, les versionner est un confort. Sinon, le répertoire brut reste dehors et le README indique d’où vient le fichier.

Les identifiants de connexion suivent la même règle, en plus strict : un jeton DHIS2, une clé d’API KoboToolbox ou un mot de passe de base de données n’apparaissent jamais dans un script, un notebook ou un commit.

import os

# Lu depuis l'environnement ; la valeur n'entre jamais dans le depot.
token = os.environ["DHIS2_TOKEN"]

Gardez la valeur dans un fichier .env couvert par .gitignore, et documentez le nom de la variable — non sa valeur — dans le README.

Notebooks et scripts font des métiers différents

Les deux ont leur place dans un projet et ne sont pas interchangeables.

Un notebook sert à regarder : explorer un nouvel export, vérifier une distribution, produire une figure à coller dans un rapport. Il s’exécute dans le désordre, porte un état invisible et se compare mal en diff, ce qui en fait un mauvais endroit pour ce qui doit s’exécuter à l’identique au trimestre prochain.

Un script sert à produire : il s’exécute de haut en bas, prend des arguments, et réussit ou échoue. Quand une exploration devient un chiffre que quelqu’un va rapporter, déplacez-la dans un script.

Le flux de travail pratique consiste à explorer dans notebooks/, puis à déplacer la partie stabilisée dans scripts/ et à la réimporter :

# scripts/read_register.py
from pathlib import Path
import pandas as pd

def read_register(path: Path) -> pd.DataFrame:
    return pd.read_csv(
        path,
        dtype={"child_id": "string", "commune": "string"},
        na_values={"muac_mm": ["-99"]},
    )
# Dans le notebook
import sys
sys.path.append(str(PROJECT / "scripts"))

from read_register import read_register

muac = read_register(RAW / "muac-screening-artibonite-2024.v1.csv")

Le notebook et le script lisent désormais le fichier de la même façon, et il n’y a qu’un seul endroit à corriger quand la sentinelle change.

Un README réellement lu

Deux commandes et trois phrases valent mieux qu’une page que personne ne termine :

# Tableaux d'indicateurs du depistage PB

Produit les taux de MAG et de MAS par commune a partir du registre de
depistage de l'Artibonite.

## Executer

    uv sync
    uv run python scripts/indicator_table.py \
        --input data/raw/muac-screening-artibonite-2024.v1.csv \
        --output outputs/tables

## Donnees

data/raw n'est pas versionne. Telechargez le registre depuis le partage
du programme et placez-le la sous son nom de fichier versionne.

Ce qui vient ensuite

Le projet a une forme et les chemins survivent à un changement de machine. L’unité suivante fait entrer les données : lire un CSV, un classeur Excel et un export à largeur fixe sans perdre un zéro initial ni se tromper de date.

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.