Bulle d’R : Bonnes pratiques à ETTIS

28 mai 2024

INTRODUCTION GÉNÉRALE

1. Utiliser les logiciels R & RStudio

Comment ça fonctionne ?

Cf. Présentation TWIX “Travailler sous R avec RStudio. Comment ça marche ?” disponible à ce lien :



https://statire.github.io/bulledr/00-TWIX/TWIX_2023_06_01

L’encodage de caractères

  • L’encodage c’est une table de correspondance entre l’ordinateur et la langue humaine (français, anglais, etc.)

  • Il existe plusieurs encodages : ASCII, ISO 8859-15 (latin-9 ou Occidental (euro)), UTF-16, UTF-8, et bien d’autres encore

  • Suivant le système d’exploitation utilisé, l’encodage par défaut n’est pas le même

    • Sous Windows par exemple, l’encodage par défaut est généralement Windows-1252
    • Sous Linux, c’est généralement UTF-8
  • Si standards différents, problèmes lors d’échanges de fichiers (scripts ou données), qui deviennent illisibles !

  • L’encodage UTF-8 est celui qui permet, à l’heure actuelle, de convertir (vers et depuis) toutes les langues (ou presque)

  • Comment paramétrer sous RStudio ?
    Aller dans Tools > Global Option > Code > Saving > Default text encoding et mettre UTF-8

Bonne pratique

Utiliser l’encodage UTF-8 pour vos scripts et vos données !

2. Gérer les packages

Préambule : Version de R

Les packages R peuvent dépendre d’une version spécifique de R (ou version minimale)

Les nouvelles versions de R peuvent apporter des corrections, éliminer les bugs… Il est donc intéressant de faire les MAJ “majeures” de printemps : 4.2.x \(\rightarrow\) 4.3.x

Les Breaking Changes

Certaines versions de R apportent des breaking changes qui peuvent casser le fonctionnement de code fonctionnant sur des versions précédentes (ex : stringAsFactor = FALSE au lieu de TRUE avant la version 4.0).

A l’inverse, des nouvelles fonctionnalités ne vont marcher que sur des versions récentes (ex : le pipe |> à partir de R 4.1.0)

Bonne pratique

Dans les publications, pensez à intégrer la version de R utilisée dans vos analyses, ainsi que les packages (fonctions) utilisés

# Pour citer R
citation()

# Pour citer un package (ici ggplot2)
citation("ggplot2")

Rappels sur le fonctionnement des packages

  1. On installe le package
install.packages("remotes")

Cela place les fonctions du package sur votre PC.

Analogie : on achète un livre 📓 pour le mettre dans sa bibliothèque 📚

  1. On charge le package
library(remotes)

On évite au lancement de R de lancer tous les packages installés, il faut donc indiquer lors de chaque session les packages à charger

Analogie : on sort le livre de la bibliothèque et on l’ouvre pour utiliser son contenu 📖

Alternative au library, le préfixage


La notation

dplyr::filter(iris, Species == "setosa")

Peut remplacer le code

library(dplyr)
filter(iris, Species == "setosa")

Trois avantages

  • Eviter les conflits si 2 packages ont une fonction au même nom (ex : filter() existe également dans le package {stats})
  • Identifier quelle fonction provient de quel package
  • Ne pas charger tout un package pour une seule fonction

Quelques mises en garde

  • Les fonctions provenant de packages tels que ceux du tidyverse proposent énormément de fonctionnalités pratiques, utiles, fonctionnelles par rapport aux fonctionnalités classiques de R
  • MAIS elles ont un cycle de développement très dynamique pouvant mener à des fonctions rapidement deprecated ou superseded

Bonne pratique

  • Privilégier, lorsque c’est possible, les fonctions/packages les plus stables possible

3. Structurer ses scripts

Penser reproductibilité

Un principe : on code pour les autres, en organisant son travail et en automatisant le plus possible

Bonnes pratiques

  • Noms des fichiers & variables explicites, suivant les conventions de nommage (cf. Section 5.1)
  • Distinguer variables d’origine et variables créées en adoptant une règle de convention (par ex. utiliser recod en préfixe ou suffixe du nom des variables)
  • Utilisation des chemins relatifs dans les programmes pour exécuter sans problème le code sur un autre ordinateur
  • Coder de façon compréhensible avec des commentaires (aucune documentation supplémentaire ne devrait être fournie). L’ajout des commentaires se fait en ajoutant # en début de ligne (raccourci clavier CRTL + MAJ + C)
  • Identification de l’ordre d’exécution des programmes pour ré-exécution facilitée de tous les programmes

A noter

Ces grands principes ne sont pas exclusifs à R, ils sont valables quel que soit le langage de programmation

Respecter des règles pour faciliter la lecture (1/2)

  • L’opérateur d’affectation est <-

  • Retour à la ligne régulièrement (la longueur maximale recommandée d’une ligne est 80 caractères) et après chaque pipe (%>% ou |>)

  • L’indentation se fait grâce à la touche TAB. Le raccourci Ctrl+I sert à réindenter les lignes de code sélectionnées

  • Les opérateurs qui lient les objets entre eux (=, +, -, <-, etc.) sont entourés d’espaces

  • Les opérateurs qui modifient un objet ou sélectionnent une partie d’un objet (:, !!, $, @, [, ], [[, ]]) ne sont pas entourés d’espaces

# On écrit 
1 + 1 = 2
dataframe$variable

# et non 
1+1=2
dataframe $ variable

Respecter des règles pour faciliter la lecture (2/2)

  • On insère un espace après la virgule mais pas avant, comme en français !

  • On ne met pas d’espace avant ou après les parenthèses

  • En revanche, les opérateurs de comparaison doivent être entourés d’espace pour ne pas être mal interprétés par R

# On écrit
mean(x, na.rm = TRUE)  
1 < -10

# et non 
mean ( x , na.rm = TRUE )
1<-10

A noter

RStudio signale les erreurs dans la marge des scripts

Structurer son code

Bonnes pratiques

  • Commencer l’écriture du script par les métadonnées (titre auteur, date, version de R, encodage, etc.)
  • Ajouter la liste des packages utilisés et leur version
# "à la main" lorsqu'on charge les packages
library(tidyverse)    # v1.3.2
library(dplyr)        # v1.1.0

# automatique
packages_utilises <- sessionInfo()
  • Structurer en parties, sous-parties, grâce au raccourci CTRL + MAJ + R ou à l’addin strcode
#  Titre 1 -------------------------------------
## Titre 2 -------------------------------------

# ou bien 

#   ____________________________________________________________________________
#   Titre 1                                                                 ####

##  ............................................................................
##  Titre 2                                                                 ####

Si on n’est pas à l’aise avec l’écriture de codes…

Il existe des alternatives ‘clic-bouton’ :

  • le package/addin {esquisse} pour créer des graphiques en ggplot

  • le package {Factoshiny} pour améliorer facilement et de façon interactive les graphiques issus d’analyses factorielles (ACP, ACM, AFM, etc.) pour les rendre beaucoup plus lisibles

  • {R Commander}, une interface utilisateur graphique (GUI)

Bonne pratique

Penser à récupérer les lignes de codes générées par ces utilitaires et à les stocker dans des scripts !

4. Nommer ses données

Utiliser des conventions de nommage

  • allowercase : tout en minuscule, sans séparateur
  • period.separated : tout en minuscule, mots séparés par des points
  • underscore_separated : tout en minuscule, mots séparés par un underscore (_)
  • lowerCamelCase : première lettre des mots en majuscule, à l’exception du premier mot ; et si nom simple, tout en minuscule
  • UpperCamelCase : première lettre des mots en majuscule, y compris le premier et même lorsque le nom est composé d’un seul mot

Bonne pratique

Possibilité de mixer les conventions mais garder une cohérence afin de faciliter la compréhension des fichiers et du code

Mise en garde

R est sensible à la casse ce qui signifie que variable et Variable sont deux objets différents.

Nommer les fichiers et les objets

  • Pour les fichiers, on peut les nommer avec la structure numero_nom_millesime.extension, sans symboles spéciaux dans le nom
    Rappel des symboles spéciaux : -.,;:\/$^`, caractères accentués, etc.

Exemple : 01_import_donnees_20230606.R

  • Pour les variables, il est recommandé d’utiliser un nom

Exemple : temperature_max

  • Pour les fonctions, il est recommandé d’utiliser un verbe

Exemple : create.map serait une fonction qui permettrait de créer une carte

Bonne pratique

Pour les variables, comme pour les fonctions :

  • ne pas utiliser T ou F pour nommer des variables (ce sont les abréviations de TRUE et FALSE)
  • ne pas utiliser de noms qui sont déjà des fonctions de R

Une aide pour écrire les scripts de façon cohérente Tidyverse Style Guide

5. Importer ses données

Importer divers types de données

Quels types de données peuvent être importés ?

  • Données dans les formats “plats” ou formats délimités (.csv, .txt)
  • Données issues d’Excel ou d’autres logiciels de statistique (Stata, SPSS, etc.)
  • Données stockées dans des bases de données relationnelles

Bonne pratique

Bien étudier son jeu de données à importer, en se posant les questions suivantes :

  1. La première ligne contient-elle le nom des variables ?
  2. Quel est le séparateur des colonnes ? (. , ; \t)
  3. Quel est le caractère utilisé pour indiquer les décimales ? Le point (à l’anglo-saxonne) ou la virgule (à la française) ?
  4. Les valeurs textuelles sont-elles encadrées par des guillemets ? Si oui, s’agit-il de guillemets simples () ou de guillemets doubles (") ?
  5. Y a-t-il des valeurs manquantes ? Si oui comment sont-elles indiquées ?

Comment importer les différents fichiers ?

Type Base R Tidyverse Séparateur de colonnes Séparateur décimal
Délimité read.csv() readr::read_csv() , .
read.csv2() readr::read_csv2() ; ,
read.table() readr::read_table() .
read.delim() readr::read_delim() \t .
read.delim2() readr::read_delim2() \t ,
Excel xlsx::read.xlsx() readxl::read_excel()
SPSS foreign::read.spss() haven::read_spss() ou haven::read_sav()
Stata foreign::read.dta() haven::read_stata()
SAS foreign::read.ssd() haven::read_sas()
dBase foreign::read.dbf() -

Exemple pour un fichier .csv

# En langage R de base
read.csv(file, header = TRUE, sep = ",", dec = ".")
# En "tidyverse"
readr::read_csv(file, col_names = TRUE)

Le concept de données tidy

Jeu de données “rangé” :

  • chaque variable est dans une colonne
  • chaque observation est dans une ligne
  • chaque valeur est dans une cellule

Mise en garde

On a des fichiers de données qui ne respectent pas toujours ces règles :

  • en-têtes de colonnes ne sont pas des noms mais des valeurs
  • plusieurs variables stockées dans une colonne
  • variables stockées dans les lignes et les colonnes
  • plusieurs types d’observations stockés dans le même tableau, etc.

“Ranger” ses données

Solution pour ranger ses données = les verbes de tidyr :

  • pivot_longer() : transformer des colonnes en lignes
  • pivot_wider() : transformer des lignes en colonnes
  • separate() : séparer une colonne en plusieurs colonnes
  • separate_rows() : séparer une colonne en plusieurs lignes
  • unite() : regrouper plusieurs colonnes en une seule
  • extract() : créer de nouvelles colonnes à partir d’une colonne de texte
  • complete() : compléter des combinaisons de variables manquantes

Besoin d’examiner rapidement vos données dans Excel ?

Utilisez l’addin viewxl pour exporter interactivement des data frame de l’environnement global vers Excel

  • avec la fonction view_in_xl
  • dans la console :
viewxl::view_in_xl(diamonds)

6. Exporter ses résultats

Exporter les graphiques

  • Directement via l’onglet ‘Plots’ Cliquer sur ‘Export’ qui donne accès à trois options différentes :

    • save as image
    • save as PDF
    • copy to clipboard
  • Dans un script, avec les fonctions jpeg(), png(), bmp() ou tiff() ou pdf() du package {grDevices}

png(filename = "fichier.png")
ggplot(...)
dev.off()
  • On préfèrera utiliser la fonction ggsave du package {ggplot2}
ggplot(...) +
  ...
ggsave(filename = name.extension)

Exporter les tableaux

Comme on importe divers formats de données, on peut exporter les données depuis R vers divers formats

Type de fichier Base R Tidyverse
.txt write.table() readr::write_delim(delim = "\t")
.csv write.csv() readr::write_csv()
.xlsx openxlsx2::write_xlsx() OU writexl::write_xlsx() -
.dbf foreign::write.dbf() -
.sav (SPSS) foreign::write.foreign(package = "SPSS") haven::write_sav()
.dta (Stata) foreign::write.dta() haven::write_dta()

COMMENT ORGANISER SON TRAVAIL ?

7. Travailler en projets

Créer un projet sous RStudio

À partir de l’icône dédiée en haut à droite de RStudio

Créer un projet sous RStudio

Sélectionner l’option “New project”, puis l’option “New Directory” et enfin “Empty Project

Exemples d’arborescence

Exemples de structurations
(chacun s’organisera de la façon qu’il juge la plus adaptée à ses usages)

A noter

Le plus important, ce sont les données initiales et les scripts de traitements.

Coup de pouce : Le package {InraeThemes}



# install.packages("remotes")
remotes::install_github("davidcarayon/InraeThemes")
InraeThemes::new_analysis()


COMMENT ANALYSER SES DONNÉES ?

8. Outils d’exploration

Fonction summary()

  • Utile pour avoir une vue résumée d’une variable
  • S’applique à tout type d’objet, y compris un data frame entier, et s’adapte à la nature des variables contenues
data(iris)
iris %>% 
  summary()
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
 Median :5.800   Median :3.000   Median :4.350   Median :1.300  
 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
       Species  
 setosa    :50  
 versicolor:50  
 virginica :50  
                
                
                

Fonction glimpse() du package {dplyr}

Permet de visualiser de manière condensée le contenu d’un tableau de données

data(iris) 
iris %>% 
  dplyr::glimpse()
Rows: 150
Columns: 5
$ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
$ Sepal.Width  <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
$ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
$ Petal.Width  <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
$ Species      <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…

Fonction describe() du package {questionr}

Décrit également les différentes variables d’un tableau de données

data(iris) 
iris %>% 
  questionr::describe()
[150 obs. x 5 variables] tbl_df tbl data.frame

$Sepal.Length: 
numeric: 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
min: 4.3 - max: 7.9 - NAs: 0 (0%) - 35 unique values

$Sepal.Width: 
numeric: 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
min: 2 - max: 4.4 - NAs: 0 (0%) - 23 unique values

$Petal.Length: 
numeric: 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
min: 1 - max: 6.9 - NAs: 0 (0%) - 43 unique values

$Petal.Width: 
numeric: 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
min: 0.1 - max: 2.5 - NAs: 0 (0%) - 22 unique values

$Species: 
nominal factor: "setosa" "setosa" "setosa" "setosa" "setosa" "setosa" "setosa" "setosa" "setosa" "setosa" ...
3 levels: setosa | versicolor | virginica
NAs: 0 (0%)

Fonction tbl_summary() du package {gtsummary}

Permet la production de tableaux croisés et autre tables complexes prêtes pour publication. S’appuie sur Great Tables ({gt})

data(iris) 
iris %>% 
  gtsummary::tbl_summary()
Characteristic N = 1501
Sepal.Length 5.80 (5.10, 6.40)
Sepal.Width 3.00 (2.80, 3.30)
Petal.Length 4.35 (1.60, 5.10)
Petal.Width 1.30 (0.30, 1.80)
Species
    setosa 50 (33%)
    versicolor 50 (33%)
    virginica 50 (33%)
1 Median (IQR); n (%)

Fonction dfSummary() du package {summarytools}

Présentation des résultats dans un tableau, pour variables QN & QL

data(iris) 
iris %>%  
  summarytools::dfSummary(graph.col = FALSE)
Data Frame Summary  
iris  
Dimensions: 150 x 5  
Duplicates: 1  

-------------------------------------------------------------------------------------
No   Variable       Stats / Values          Freqs (% of Valid)   Valid      Missing  
---- -------------- ----------------------- -------------------- ---------- ---------
1    Sepal.Length   Mean (sd) : 5.8 (0.8)   35 distinct values   150        0        
     [numeric]      min < med < max:                             (100.0%)   (0.0%)   
                    4.3 < 5.8 < 7.9                                                  
                    IQR (CV) : 1.3 (0.1)                                             

2    Sepal.Width    Mean (sd) : 3.1 (0.4)   23 distinct values   150        0        
     [numeric]      min < med < max:                             (100.0%)   (0.0%)   
                    2 < 3 < 4.4                                                      
                    IQR (CV) : 0.5 (0.1)                                             

3    Petal.Length   Mean (sd) : 3.8 (1.8)   43 distinct values   150        0        
     [numeric]      min < med < max:                             (100.0%)   (0.0%)   
                    1 < 4.3 < 6.9                                                    
                    IQR (CV) : 3.5 (0.5)                                             

4    Petal.Width    Mean (sd) : 1.2 (0.8)   22 distinct values   150        0        
     [numeric]      min < med < max:                             (100.0%)   (0.0%)   
                    0.1 < 1.3 < 2.5                                                  
                    IQR (CV) : 1.5 (0.6)                                             

5    Species        1. setosa               50 (33.3%)           150        0        
     [factor]       2. versicolor           50 (33.3%)           (100.0%)   (0.0%)   
                    3. virginica            50 (33.3%)                               
-------------------------------------------------------------------------------------

Explorer les données manquantes avec la fonction vis_miss() du package {visdat}



library(visdat)
vis_miss(airquality)

L’exploration en un bouton avec {DataExplorer}

  • plot_histogram(), plot_bar(), plot_density() proposent des graphiques en sélectionnant les variables pertinentes à chaque cas

  • Rapport automatique, au format HTML avec create_report() : Visualisations graphiques (distributions, analyses de corrélations, ACP), état des lieux du jeu de données, concernant notamment le type des variables ou les données manquantes

Bonus

{FactoInvestigate} pour quelque chose de similaire mais spécifique à des sorties d’analyses multivariées !

A noter

Fonctions utiles pour première exploration des données, sans autre programmation nécessaire.

Pour aller plus loin… programmation lettrée (Rmarkdown/Quarto) [session dédiée si nécessaire]

9. Quelques packages conseils

{questionr} : particulièrement dédié au traitement de données d’enquêtes (variables qualitatives)


library(questionr)
data(hdv2003)
freq(hdv2003$qualif, cum = TRUE, total = TRUE, sort = "dec")
                            n     %  val%  %cum val%cum
Employe                   594  29.7  35.9  29.7    35.9
Ouvrier qualifie          292  14.6  17.7  44.3    53.6
Cadre                     260  13.0  15.7  57.3    69.3
Ouvrier specialise        203  10.2  12.3  67.4    81.6
Profession intermediaire  160   8.0   9.7  75.4    91.3
Technicien                 86   4.3   5.2  79.8    96.5
Autre                      58   2.9   3.5  82.7   100.0
NA                        347  17.3    NA 100.0      NA
Total                    2000 100.0 100.0 100.0   100.0

{skimr} : un summary sous stéroïdes 💪

library(skimr)
skimr::skim(mtcars)

{tidymodels} : le tidyverse de la modélisation



  • Propose une interface unifiée à tous les types de modèles (lm, glm, randomForests, xgboost, etc.)

{ggstatsplot} : combiner statistiques et représentations graphiques


library(ggstatsplots)


{sf} & {mapsf} : traitements spatiaux et cartographie comme un pro

Analyses factorielles

Deux grandes écoles

library(ade4)
library(adegraphics)

library(FactoMineR)
library(factoextra) # + FactoInvestigate + FactoShiny

🏆 en général privilégié

{PCAmixdata} : l’analyse de données mixtes

Chavent, M., Kuentz-Simonet, V., Labenne, A., & Saracco, J. (2014). Multivariate analysis of mixed data: The R package PCAmixdata. arXiv preprint arXiv:1411.4911.

Police et ligature : Fira Code

Police à installer ici

ALLER PLUS LOIN… ET SORTIR DE R & RStudio

10. Des outils pour valoriser, communiquer ses travaux

Markdown


Quarto

  • Quarto est le successeur de Rmarkdown qui se veut plus généraliste et polyglotte
  • ⚠️ Rmarkdown n’est pas mort pour autant !

Rmarkdown : centré sur R

Quarto : Approche plus généraliste

Une extension INRAE !



Plus d’informations sur Github

Renv : Figer ses versions de packages R


Sans {renv}

Les packages sont communs pour tous les projets

Avec {renv}

Le projet 1 peut utiliser dplyr 1.0.2 et le projet 2 dplyr 0.8.2

Git & Gitlab/Hub

Pourquoi utiliser Git ?

  • Garder en mémoire chaque modification de chaque fichier, pourquoi elle a eu lieu, quand et par qui

  • Faciliter le développement collaboratif : fusion des différentes modifications

  • Revenir aux versions précédentes (+ sauvegarde du travail)

  • Déployer son travail en ligne (Pages)

Shiny : Des application web

  • Shiny est un package R qui permet de développer facilement des applications web interactives dans une syntaxe R très simple (pouvant être complétée par du HTML / CSS / JS pour les applications les plus abouties).

  • Outil principalement utilisé pour l’analyse et la visualisation de données, ou encore la mise à disposition de code R “complexe” en presse-bouton

  • Excellent outil de valorisation et diffusion des résultats de recherche


POUR CONCLURE

Ne soyons pas trop exigeants…

Merci ! Des questions ?

Slides consultables ici :
https://statire.github.io/bulledr/01-bonnes_pratiques/

Slides made with …

https://github.com/davidcarayon/quarto-inrae-extension