Une formation aux bonnes pratiques avec Git et R
R
et Git
(page d’accueil)Origine : communauté des développeurs logiciels
Constats :
Conséquence : un ensemble de règles informelles, conventionnellement acceptées comme produisant des logiciels fiables, évolutifs et maintenables
L’activité du statisticien / datascientist tend à se rapprocher de celle du développeur :
projets intenses en code
projets collaboratifs et de grande envergure
complexification des données et donc des infrastructures
déploiement d’applications pour valoriser les analyses
Source : Peng R., Reproducible Research in Computational Science, Science (2011)
Une reproductibilité parfaite est coûteuse
Git
est un standard atteignable et efficient
Note
Quel socle de bonnes pratiques pour les projets statistiques en ?
Un point de départ commun
Un point de départ commun
Une structuration de projet plus viable
Git
1️⃣ Le contrôle de version : pourquoi faire ?
2️⃣ Le contrôle de version avec Git
pour en finir avec ça :
ou ça :
ou encore ça :
prior <- read_csv(prior_path)
prior <- prior %>%
select(id, proba_inter, proba_build, proba_rfl) %>%
separate(id, into = c('nidt', 'grid_id'), sep = ":") %>%
group_by(nidt) %>%
mutate(
proba_build = proba_build/sum(proba_build),
proba_rfl = proba_rfl/sum(proba_rfl),
) %>%
unite(col = "id", nidt, grid_id, sep = ":")
# Test
# prior_test <- prior %>%
# mutate(
# proba_inter = round(proba_inter, 4)
# proba_build = round(proba_build, 4)
# proba_rfl = round(proba_rfl, 4)
# )
write_csv(prior_round, "~/prior.csv")
Pour arriver à ça :
Source : ThinkR
Un modèle distribué
Source : specbee.com
Qui permet l’expérimentation en toute sécurité
Source : lutece.paris.fr
Quel que soit l’environnement de travail
Avec des outils pour faciliter la collaboration
Une vitrine pour les projets et l’organisation
Construire et naviguer à travers l’historique de son projet
La collaboration rendue simple et efficace
Améliorer la reproductibilité de ses projets
Améliorer la visibilité de ses projets
Git
L’utilisation de Git
nécessite certaines notions préalables:
filesystem
Linux
Mais
Git
sont très informatifsRStudio
, Sublime Merge
, VS Code
) qui facilitent l’apprentissageGit
, GitHub
, GitLab
… quelles différences ?Git
est un logiciel ;RStudio
, VS Code
…)Git
, GitHub
, GitLab
… quelles différences ?GitHub
et GitLab
sont des forges logiciellesAstuce
GitHub
: utilisation pour les projets open-sourceGitLab
: utilisation pour les projets internesremote
)origin
Source : Git Documentation
Action | Commande |
---|---|
Cloner un projet | git clone [url-to-git-repo] |
Afficher les changements | git status |
Retrouver l’URL du dépôt distant | git remote -v |
Action | Commande |
---|---|
Ajouter des changements à l’index de Git (stage fixes) |
Un seul fichier : git add <file-name> Tous les fichiers déjà indexés : git add -u Tous les fichiers ⚠️ : git add -A |
Warning
La méthode git add -A
peut amener à suivre les modifications de fichiers qui ne devraient pas l’être (par exemple, des données).
Il est recommandé de bien réfléchir avant de l’utiliser (ou d’avoir un bon .gitignore
)
Action | Commande |
---|---|
Faire un commit |
git commit -m "message" |
Pousser les changements locaux vers le dépôt distant (branche master ) |
git push origin master |
Récupérer les changements sur le dépôt distant (branche master ) |
git pull origin master |
git clone https://github.com/username/projet.git
git clone git@github.com:username/projet.git
git clone https://gitlab.insee.fr/username_or_groupname/projet.git
git clone git@gitlab.insee.fr:username_or_groupname/projet.git
Préparation de l’environnement de travail
GitHub
GitHub
en incluant un fichier README
RStudio
. Dans l’onglet de configuration Git
du service, fixer la durée du Cache
pour le stockage des identifiants GitHub
à une valeur suffisamment élevéeRStudio
du Datalab
):
File
→ New project
→ Version Control
→ Git
GitHub
SSP Cloud
(ou un gestionnaire de mot de passe) :
Mon Compte
-> Git
-> Token d'accès personnel pour Forge Git
GitHub
et le tokenPréparation de l’environnement de travail
gitlab.insee.fr
RStudio
. Dans l’onglet de configuration Git
du service, fixer la durée du Cache
pour le stockage des identifiants Gitlab
à une valeur suffisamment élevéeRStudio
de la plateforme LS3
):
File
→ New project
→ Version Control
→ Git
gitlab.insee.fr
LS3
(ou un gestionnaire de mot de passe) :
Mon Compte
-> Git
-> Token d'accès personnel pour Forge Git
❓ Question : qu’est ce qui différencie le projet cloné d’un projet quelconque ?
Premiers commits
scripts
script1.R
et script2.R
, chacun contenant quelques commandes R
de votre choixRStudio
commit
, auquel on donnera un message descriptif pertinentscript1.R
et modifier le contenu du fichier script2.R
RStudio
RStudio
❓ Question : à ce stade, le dépôt du projet sur GitHub
/ Gitlab
(remote
) a-t-il été modifié ?
Interactions avec le dépôt distant
push
pour intégrer les changements locaux au projet distantGitHub
/ Gitlab
Que versionne-t-on ?
.html
, .pdf
, modèles…)Note
Pour définir des règles qui évitent de committer tel ou tel fichier, on utilise un fichier nommé .gitignore
.
Si on mélange du code et des éléments annexes (output, données…) dans un même dossier, il faut consacrer du temps à ce fichier.
Des modèles de .gitignore
existent sur internet, par exemple celui-ci pour les projets .
N’hésitez pas à y ajouter des règles conservatrices (par exemple *.csv
), comme cela est expliqué dans la documentation utilitR
.
Format des commits
Le fichier .gitignore
L’objectif de cette application est de créer le fichier .gitignore
, qui permet de spécifier l’ensemble des fichiers et/ou dossiers que l’on souhaite exclure de l’indexation faite par Git
. Il doit se situer à la racine du projet.
.gitignore
à la racine du projet (attention à ne pas ajouter d’extension au fichier, type .txt
)data
à la racine du projet et créer à l’intérieur de celui-ci un fichier data/raw.csv
avec une ligne de données quelconque.gitignore
qui exclue le dossier data/
, et vérifier que la règle fonctionne*.pdf
et *.html
, et vérifier que la règle fonctionne❓ Question : que se passe-t-il lorsque l’on ajoute au .gitignore
des fichiers qui ont déjà été commit sur le projet Git ?
Des fichiers .gitignore
standards
Dans cette application, nous avons généré le fichier .gitignore
manuellement. En pratique, il existe des .gitignore standards adaptés pour chaque langage de programmation, qui implémentent déjà de nombreuses règles pertinentes. Le mieux est donc de partir du .gitignore R pour tout nouveau projet R
, et de rajouter les règles spécifiques que l’on souhaite appliquer au projet.
utilitR
propose plusieurs chapitres sur Git
Git
Git
sur AUS
Git
!R
1️⃣ Qualité du code
2️⃣ Structure des projets
3️⃣ Formats de données
Préparation de l’environnement de travail
Github
en incluant un fichier README
et un .gitignore
(chercher le modèle R
dans les suggestions)RStudio
. Dans l’onglet de configuration Git
du service, fixer la durée du Cache
pour le stockage des identifiants GitHub
à une valeur suffisamment élevée (conseil: 36000)RStudio
du Datalab
):
File
→ New project
→ Version Control
→ Git
get_data.R
en copiant le contenu de ce fichier, puis l’exécuterscript.R
dans votre dépôt en copiant le contenu de ce fichier. Ne l’exécutez pas, c’est l’objet de l’exercice suivant..gitignore
. Que signifie-t-elle ?Git
a ajouté)Préparation de l’environnement de travail
GitLab
RStudio
. Dans l’onglet de configuration Git
du service, fixer la durée du Cache
pour le stockage des identifiants GitHub
à une valeur suffisamment élevéeRStudio
de LS3
):
File
→ New project
→ Version Control
→ Git
get_data.R
en copiant le contenu de ce fichier, puis l’exécuterscript.R
dans votre dépôt en copiant le contenu de ce fichier.gitignore
. Que signifie-t-elle ?D’une vision utilitariste du code à une vision du code comme outil de communication
Favoriser la lisibilité et la maintenabilité
Faciliter la réutilisation
Assurer la transparence méthodologique
1️⃣ Adopter les standards communautaires
2️⃣ Eviter la duplication de code
3️⃣ (Auto)-documenter son code
4️⃣ Isoler la configuration du code
“Good coding style is like correct punctuation: you can manage without it, butitsuremakesthingseasiertoread”
Respecter les conventions du langage dans lequel il est rédigé
Il existe un guide de référence pour bien coder en R
: le Tidyverse style guide.
Deux outils pratiques aident à respecter les standards :
Astuce
Dans le cas de :
Règle d’or
Il faut utiliser une fonction dès qu’on utilise une même portion de code plus de deux fois (don’t repeat yourself (DRY))
Règles pour écrire des fonctions pertinentes
Comment bien documenter un script ?
roxygen2
.L’auto-documentation en pratique
👎 La documentation pallie des mauvais nommages
# Utilise string si x est non manquant et non vide
if (!is.na(x) && nzchar(x)) {
use_string(x)
}
👍 Les nommages suffisent à comprendre le code
x_is_not_empty_string <- (!is.na(x) && nzchar(x))
if (x_is_not_empty_string) {
use_string(x)
}
README
ou des fichiers spécialisés (DESCRIPTION
ou renv.lock
)package::fonction()
Exemple
package1
et package2
contiennent chacun une fonction appelée super_fonction
.package2
est chargé après package1
, alors la fonction de package1
est automatiquement masquée et super_fonction
désigne par défaut la fonction de package2
.package1::superFonction
et package2::superFonction
Les secrets (mots de passe, tokens, etc.) sont des données sensibles
Quelques principes de sécurité essentiels
En pratique, deux recommendations selon l’usage
.gitignore
)R
Partie 1 : vérification du bon fonctionnement du code
Un code reproductible est avant toute chose un code fonctionnel !
script.R
de s’exécuter correctement, et les corriger.Session
> New Session
(ou Ctrl+Maj+F10)Les pièges que cet exercice vous montre
Partie 2 : premiers standards de qualité
R
lintr
et styler
1.tidyverse
avec lintr::use_lintr(type = "tidyverse")
script.R
avec lintr::lint("script.R")
.
script.R
avec styler::style_file("script.R")
.styler
est un formatter peu intrusif.Partie 3 : une meilleure gestion des packages utilisés
package::fonction
pour les packages rarement utilisés dans le script.tidyverse
au complet est rarement utile. N’importer à la place que les packages effectivement utilisés dans le script.A propos du rm(list = ls())
(le supprimer !)
Cette commande est une mauvaise pratique.
On la retrouve encore dans trop de scripts car elle est utilisée pour de mauvaises raisons. Elle ne remets pas à 0 votre environnement: elle supprime juste les données de celui-ci, sans toucher au reste (packages importés, etc.).
Il vaut mieux gérer cela en changeant les options de puis redémarrer la session (CTRL+SHIFT+F10)
Partie 4 : (auto-)documentation du code
L’objectif de cet exercice est de remettre de l’ordre dans le script, cela le rendra bien plus lisible.
library
pour les mettre tous ensemble au début du script.# TITRE NIVEAU 1 ------------
et ## TITRE NIVEAU 2 ==========
Au passage, vous pouvez changer les noms de certains objets pour les rendre moins cryptiques (df3
n’est pas très clair).
Partie 5 : une meilleure gestion des secrets
Dans cette application, on va explorer deux manières possibles de gérer les secrets proprement.
Première possibilité : de manière interactive.
rstudioapi
, qui permet de demander à l’utilisateur d’entrer le secret à l’aide d’un pop-up interactif.⚠️ Cette solution nécessite l’exécution du code dans un environnement RStudio
, ce qui implique un usage en self.
Deuxième possibilité : via les variables d’environnement.
.Renviron
(voir cette fiche UtilitR pour plus d’info sur ce fichier) à la racine du projet et y ajouter une ligne JETON_API=xxx
en remplaçant xxx
par la valeur du jeton.api_token
à l’aide de la fonction Sys.getenv..Renviron
est bien renseigné dans le .gitignore
. Si ce n’est pas le cas, ajouter la règle et vérifier son bon fonctionnement, puis commit/push.Checkpoint
get_data.R
script.R
.gitignore
{fig-align=“center”}
Favoriser la lisibilité et la maintenabilité
Construire des projets reproductibles
├── report.Rmd
├── correlation.png
├── data.csv
├── data2.csv
├── fig1.png
├── figure 2 (copy).png
├── report.pdf
├── partial data.csv
├── script.R
└── script_final.R
Source : eliocamp.github.io
Utiliser les projets RStudio
Organiser son projet en sous-dossiers
Donner des noms pertinents aux fichiers
Documenter son projet
(Faire de son projet un package)
Git
, on s’assure de toujours travailler dans un projet RStudio !├── data
│ ├── raw
│ │ ├── data.csv
│ │ └── data2.csv
│ └── derived
│ └── partial data.csv
├── R
| ├── script.R
│ ├── script_final.R
│ └── report.Rmd
└── output
├── fig1.png
├── figure 2 (copy).png
├── figure10.png
├── correlation.png
└── report.pdf
├── data
│ ├── raw
│ │ ├── dpe_logement_202103.csv
│ │ └── dpe_logement_202003.csv
│ └── derived
│ └── dpe_logement_merged_preprocessed.csv
├── R
| ├── preprocessing.R
│ ├── generate_plots.R
│ └── report.Rmd
└── output
├── histogram_energy_diagnostic.png
├── barplot_consumption_pcs.png
├── correlation_matrix.png
└── report.pdf
Le fichier README.md
, situé à la racine du projet, est à la fois la carte d’identité et la vitrine du projet
Idéalement, il contient :
Quelques modèles de README.md
complets :
devtools
et usethis
Partie 1 : modularisation du projet
R/functions.R
.fonction_de_stat_agregee
un nom plus pertinent et des noms d’arguments plus transparents.
fonction_de_stat_agregee
selon le standard roxygen
. Vous pouvez vous aider d’une IA assistante comme ChatGPT
, Claude
ou Copilot
, rien n’est sensible dans ce code (d’ailleurs rien de sensible ne doit être dans du code !).fonction_de_stat_agregee
dans cette documentation.script.R
, appeler en début de chaîne ces fonctions avec source("R/functions.R", encoding = "UTF-8")
.script.R
.get_data.R
et script.R
pour rendre plus intelligible la chaîne de production..gitignore
puis commit/push.Partie 2 : création d’un package (FACULTATIF)
usethis::create_package()
R
du package un module stat.R
et y copier la fonction de statistique agrégéedevtools::load_all()
et vérifier que la fonction marche correctementDESCRIPTION
. En particulier, spécifier les dépendances nécessaires (Imports
) et facultatives (Suggests
)devtools::document()
. Où est-elle stockée et sous quel format ??ma_fonction
GitHub
est y mettre le code du package. Vérifier que le package peut être installé en local avec la fonction devtools::install_github()
.Checkpoint
script.R
R/functions.R
{fig-align=“center”}
CSV
Parquet
Exemple: Recensement de la Population
Parquet
Parquet
L’art de bien partitionner
Partitionner par une/des variable(s) d’intérêt (ex : millésime x département)
Eviter de créer de nombreux petits (< 128Mo) fichiers
Parquet
Gestion native des méta-données
Interopérable
Open-source
Parquet
Arrow
) VS orientation BDD (DuckDB
)tidyverse
Exemple d’une requête lazy
n_logements_depcom <- achille |>
filter(dep %in% c("01", "02", "03")) |> # Récupère seulement les données nécessaires
select(idlogement, depcom) |> # Récupère seulement les colonnes nécessaires
group_by(depcom) |>
summarise(n_logements = n()) |>
collect() # Les calculs ne sont effectués qu'à cette étape !
Partie 0: préparation de l’exercice
download_data
en copiant-collant le contenu de ce fichier. Exécuter ce script, il crée les fichiers nécessaires pour ces exercices.R/benchmarking_functions.R
en copiant-collant le contenu de ce fichierR
qui servira de bac à sable pour tester le format Parquet
.columns_subset <- c(
"REGION", "AGED", "ANAI", "CATL", "COUPLE",
"SEXE", "SURF", "TP", "TRANS"
)
filename_sample_csv <- "data/RPindividus_24.csv"
filename_sample_parquet <- gsub("csv", "parquet", filename_sample_csv)
filename_full_parquet <- gsub("_24", "", filename_sample_parquet)
filename_full_csv <- gsub("parquet", "csv", filename_full_parquet)
Partie 1: Ouvrir un fichier Parquet
et comprendre la logique de la lecture par bloc
Lecture du fichier avec read_parquet
du package arrow
:
filename_sample_parquet
. Pour mesurer le temps d’exécution, vous pouvez utiliser le squelette de code suggéré ci-dessous 👇️.select(any_of(columns_subset))
). Mesurez-vous une différence dans les temps de traitement ?Lecture du fichier avec open_dataset
du package arrow
:
open_dataset(filename_sample_parquet)
. Regarder la classe de cet objet.head(5)
après open_dataset
. Observer l’objet obtenu (sortie en console, classe).collect()
après cette chaîne.open_dataset(filename_sample_parquet) %>% collect()
. Ajouter le filtre select(any_of(columns_subset))
. Sa place influence-t-elle la vitesse de votre processus ?Comparaison à la lecture d’un CSV:
readr::read_csv
pour lire le fichier (chemin filename_sample_csv
) avec et sans l’argument col_select
. Avez-vous des gains de performance si vous ne lisez le fichier qu’avec ces colonnes ?❓️ Quelle méthode retenir pour lire un Parquet
avec Arrow
?
Partie 2: Un format léger et efficace
Dans cet exercice, vous devrez utiliser open_dataset
pour lire les Parquet
.
filename_full_parquet
.
filter(REGION == 24)
. Comprenez-vous pourquoi vous ne bénéficiez pas de gain de performance ?❓️ Dans quel ordre sont faits les filtres par Arrow
?
Partie 2bis (optionnelle): Pour mieux comprendre le predicate pushdown (optionnel)
duckdb
fournit une méthode EXPLAIN ANALYZE
pratique pour comprendre les optimisations faites à la lecture d’un fichier Parquet
.
R
?❓️ Dans quel ordre sont faits les filtres par Arrow
? Comment faire si on veut régulièrement filtrer nos données à partir de niveaux des variables ?
Partie 3: le Parquet partitionné
Parquet
par “REGION” et “DEPT”open_dataset(filename_full_parquet) %>%
group_by(REGION, DEPT) %>%
write_dataset("./data/RPindividus")
Arrow
pour lire les données de la Corse du Sud (code région 94, code département 2A) à partir de ce fichier partitionné❓️ Imaginons que les utilisateurs voudraient aussi se restreindre à certains types de ménages en fonction de caractéristiques:
Quand on généralise cette démarche de benchmark, on obtient le tableau de performance suivant
Partie 4: mise à jour de la chaîne de production
Nous allons mettre à jour les données utilisées pour notre chaîne de production:
❓️ Cette mise à jour des données utilisées vous est-elle apparue plus simple que les changements de l’application 1 ?
Checkpoint
main.R
R/functions.R
{fig-align=“center”}
utilitR
R
ENSAE
Slack
grrr, très dynamiqueTchap
Langage RR
à l’Insee : le salon Tchap
Insee - Outils Stats v2Les bonnes pratiques favorisent la reproductibilité et la réutilisation des projets statistiques
Des outils permettent d’appliquer les bonnes pratiques
Le coût est d’autant plus faible que l’on se place en amont du projet
Bonnes pratiques pour les projets statistiques (retour au site principal ; )