cassionAnalyse de données

Leçon 1 sur 8

Unité · Un projet qui se rouvre

Une analyse qui se rouvre un an plus tard

Projets RStudio, here(), renv, et les deux habitudes — setwd() et un espace de travail sauvegardé — qui font qu'une analyse R ne tourne que sur une machine, un seul jour.

R80 min

L’échec que cette leçon prévient

On vous demande d’expliquer le chiffre du trimestre dernier. Vous ouvrez l’analyse, l’exécutez, et obtenez un chiffre différent — ou rien du tout, parce que le paquet qui l’avait produit a avancé de deux versions.

Ce n’est pas un défaut de l’analyse. C’est l’environnement, et en R trois habitudes précises en sont la cause.

Les trois habitudes à abandonner

setwd()

setwd("/Users/marie/Bureau/nutrition")

Cela s’exécute sur exactement un ordinateur. C’est la raison la plus fréquente pour laquelle le script d’un collègue échoue sur votre machine, et le correctif n’est pas de modifier le chemin — c’est de ne plus en avoir.

rm(list = ls()) en tête de script

Cela ressemble à un départ propre et n’en est pas un. Cette instruction supprime les objets de votre espace de travail et laisse tout le reste : paquets attachés, options, répertoire de travail, tout ce qu’un .Rprofile a chargé. Un script qui en a besoin est un script non reproductible, et l’exécuter dans une session neuve est le seul véritable test.

Redémarrez R à la place — Ctrl/Cmd + Maj + F10 sous RStudio. C’est le départ propre que rm(list = ls()) prétend être.

Un espace de travail sauvegardé

RStudio propose d’enregistrer .RData à la fermeture et de le recharger au démarrage. Désactivez les deux :

Tools -> Global Options -> General
  Restore .RData into workspace at startup    [ ]
  Save workspace to .RData on exit            Never

Un espace de travail rechargé signifie que votre session contient des objets dont vous ne voyez pas le code. L’analyse paraît fonctionner parce que quelque chose de la semaine dernière est encore en mémoire, et elle cesse de fonctionner dès qu’une autre personne l’exécute.

Le projet

Un projet RStudio est un répertoire contenant un fichier .Rproj. Ouvrir le projet fixe le répertoire de travail sur ce répertoire — c’est tout le mécanisme, mais il suffit à rendre chaque chemin de votre code relatif au projet plutôt qu’à votre dossier personnel.

muac-analysis/
  muac-analysis.Rproj
  data/
    raw/            l'export tel qu'il est arrive, jamais modifie
    interim/
  outputs/
    tables/
    figures/
  R/
    read_register.R
    indicator_table.R
  renv.lock
  README.md
  .gitignore

data/raw est en lecture seule. L’export tel qu’il est arrivé est la seule chose que vous ne pouvez pas reproduire ; tout le reste est régénéré en réexécutant le code. Il n’est donc jamais modifié, jamais trié dans Excel « juste pour regarder », et une correction se pose à côté de l’original sous un nouveau nom versionné plutôt que de le remplacer.

here() plutôt qu’un chemin relatif

Un chemin relatif comme "data/raw/muac.csv" fonctionne depuis la racine du projet et casse dans un notebook, dans un document R Markdown compilé depuis un sous-répertoire, ou lorsqu’on exécute une ligne à la fois depuis un autre emplacement.

library(here)

muac <- readr::read_csv(here("data", "raw", "muac-screening-artibonite-2024.v1.csv"))

here() trouve la racine du projet — le répertoire contenant le .Rproj, ou un fichier .here, ou un répertoire .git — et construit le chemin à partir de là. Le résultat est le même d’où que le code soit lancé.

here()
#> [1] "/home/marie/muac-analysis"

Appelez here() une fois en tête de script et utilisez-le partout. Un chemin construit par paste0() avec un / ne fonctionnera pas sous Windows ; here() gère le séparateur.

renv : les versions de paquets, consignées

here() règle les chemins. Il ne fait rien pour les paquets, et ce sont les paquets qui font bouger le chiffre.

install.packages("renv")

renv::init()       # une fois par projet

renv::init() donne au projet sa propre bibliothèque et écrit renv.lock, un relevé de chaque paquet et de sa version exacte. Ensuite :

renv::snapshot()   # apres toute installation ou mise a jour
renv::restore()    # sur une autre machine, ou un an plus tard

Versionnez renv.lock. C’est la différence entre « installez le tidyverse » et « installez les versions qui ont produit ce tableau ».

Installer là où il n’y a pas d’internet

La partie que la plupart des tutoriels sautent, et celle qui compte sur un déploiement.

Sur une machine connectée, téléchargez les sources une fois :

renv::init()
renv::snapshot()

# Remplir un cache local avec tout ce que nomme le fichier de verrouillage.
renv::install()
renv::isolate()

Copiez ensuite le répertoire du projet — renv/library compris — vers le portable de terrain. renv::restore() utilisera ce qui est déjà présent plutôt que de chercher un dépôt qu’il ne peut pas voir.

Pour une machine ayant besoin de paquets non encore installés, le mécanisme général est un dépôt local :

# Sur la machine connectee
dir.create("pkgs")
download.packages(c("dplyr", "readr", "haven"), destdir = "pkgs", type = "source")

# Sur la machine hors ligne
install.packages(
  c("dplyr", "readr", "haven"),
  repos = NULL,
  type = "source",
  contriburl = paste0("file://", normalizePath("pkgs"))
)

Les paquets sources exigent un compilateur pour tout ce qui contient du C ou du C++, ce qui est fréquent. Si les machines de terrain sont sous Windows, téléchargez plutôt les binaires (type = "win.binary") depuis une machine Windows de même version de R.

Charger les paquets

library(readr)
library(dplyr)

Deux choses à ne pas faire :

N’utilisez pas require() dans un script. Il renvoie FALSE et poursuit quand le paquet est absent : le script échoue donc plus loin, sur une erreur déroutante concernant un objet inexistant. library() s’arrête sur place et vous dit quel paquet manque.

N’appelez pas install.packages() depuis un script. Un script qui installe des logiciels comme effet de bord est un script que personne ne peut relancer sans risque. L’installation, c’est renv::restore(), une fois, délibérément.

Là où deux paquets exportent le même nom — dplyr::filter() et stats::filter(), dplyr::lag() et stats::lag() — dites lequel vous voulez :

muac |> dplyr::filter(muac_mm < 125)

La forme :: vaut ses quelques caractères dans un script qui survivra au souvenir que vous avez de ce qui était attaché.

Vérifier l’environnement avant de lui faire confiance

sessionInfo()

Pour une analyse dont les chiffres comptent, préférez l’assertion à l’inspection :

stopifnot(getRversion() >= "4.2.0")
stopifnot(requireNamespace("dplyr", quietly = TRUE))

|>, le tube natif employé dans tout ce cours, exige R 4.1 ou plus récent. Si votre équipe est sur un R plus ancien, %>% de magrittr fait le même travail et le code de ces leçons fonctionne tel quel avec lui.

Ce qu’il faut remettre à un collègue

À versionner À ne pas versionner
R/, .Rproj renv/library/
renv.lock data/raw/ — voir ci-dessous
README.md outputs/
.gitignore .Rhistory, .RData
.Rproj.user/
.Rhistory
.RData
renv/library/
data/raw/
outputs/

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, et un dépôt interne le lundi peut être partagé le vendredi. Les identifiants de connexion — jeton DHIS2, clé KoboToolbox — n’apparaissent jamais dans un script :

token <- Sys.getenv("DHIS2_TOKEN")
stopifnot(nzchar(token))

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

Ce qui vient ensuite

Le projet se rouvre et les paquets sont épinglés. La leçon suivante y fait entrer un export : readr pour le CSV, readxl pour Excel, et la spécification de colonnes qui empêche un code de formation sanitaire de devenir un nombre.

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.