1.5 Code R bien structuré

Terminons ici avec quelques conseils sur la rédaction d’un code R. Bien rédiger son code est essentiel pour trois raisons :

  1. Pouvoir relire et réutiliser son code dans le futur.
  2. Permettre à d’autres personnes de bien lire et de réutiliser votre code.
  3. Minimiser les risques d’erreurs.

Ne négligez pas l’importance d’un code bien rédigé et bien documenté, vous vous éviterez ainsi des migraines lorsque vous devrez exhumer du code écrit il y a plusieurs mois.

Voici quelques lignes directrices peu contraignantes, mais qui devraient vous être utiles :

  1. Privilégier la clarté à la concision : il vaut mieux parfois scinder une ligne de code en plusieurs sous-étapes afin de faciliter la lecture de l’opération réalisée. Par exemple, si nous reprenons une ligne de code d’une section précédente où nous sélectionnions l’ensemble des colonnes du jeu de données iris comprenant le mot Length :
iris_l <- iris[names(iris)[grepl("Length",names(iris), fixed = TRUE)]]

Nous pouvons simplifier la lecture de ce code en détaillant les différentes étapes comme suit :

noms_cols <- names(iris)
sel_noms <- noms_cols[grepl("Length",noms_cols, fixed = TRUE)]
iris_l <- iris[sel_noms]
  1. Documenter et commenter son code le plus possible : il est possible d’ajouter du texte dans un code R qui ne sera pas exécuté, ce que nous appelons des commentaires. Typiquement, une ligne commençant par un # n’est pas interprétée par le logiciel. Utilisez des commentaires le plus souvent possible pour décrire les actions que vous souhaitez effectuer avec votre code. Il sera ainsi plus facile de le relire, de naviguer dedans, mais également de repérer d’éventuelles erreurs. Si nous reprenons l’exemple précédent :
# Récupération du nom des colonnes dans le DataFrame iris
noms_cols <- names(iris)

# Sélection des colonnes avec les caractères "Length"
sel_noms <- noms_cols[grepl("Length",noms_cols, fixed = TRUE)]

# Extraction des colonnes sélectionnées dans un nouveau DataFrame
iris_l <- iris[sel_noms]
  1. Éviter le code à rallonge… : typiquement, essayez de vous limiter à des lignes de code d’une longueur maximale de 80 caractères. Au-delà de ce seuil, il est judicieux de découper votre code en plusieurs lignes.

  2. Adopter une convention d’écriture : une convention d’écriture est un ensemble de règles strictes définissant comment un code doit être rédigé. À titre d’exemple, il est parfois recommandé d’utiliser le lowerCamelCase, le UpperCamelCase, ou encore de séparer les mots par des tirets bas upper_camel_case. Un mélange de ces différentes conventions peut être utilisé pour distinguer les variables, les fonctions et les classes. Il peut être difficile de réellement arrêter une telle convention, car les différents packages dans R utilisent des conventions différentes. Dans vos propres codes, il est surtout important d’avoir une certaine cohérence et ne pas changer de convention.

  3. Indenter le code : l’indentation du code permet de le rendre beaucoup plus lisible. Indenter son code signifie d’insérer, au début de chaque ligne de code, un certain nombre d’espaces permettant d’indiquer à quel niveau de profondeur nous nous situons. Typiquement, lorsque des accolades ou des parenthèses sont ouvertes dans une fonction, une boucle ou une condition, nous rajoutons deux ou quatre espaces en début de ligne. Prenons un exemple très concret : admettons que nous écrivons une fonction affichant un résumé statistique à chaque colonne d’un jeu de données si cette colonne est de type numérique. L’indentation dans cette fonction joue un rôle crucial dans sa lisibilité. Sans indentation et sans respecter la règle des 80 caractères, nous obtenons ceci :

summary_all_num_cols <- function(dataset){for(col in names(dataset)){if(class(dataset[[col]] == "numeric")){print(summary(dataset[[col]]))}}}

Avec de l’indentation et des commentaires, la syntaxe est beaucoup plus lisible puisqu’elle permet de repérer facilement trois niveaux/paliers dans le code :

# Définition d'une fonction
summary_all_num_cols <- function(dataset){
  # Itération sur chaque colonne de la fonction
  for(col in names(dataset)){
    # A chaque itération, testons si la colonne est de type numérique
    if(class(dataset[[col]] == "numeric")){
      # Si oui, nous affichons un résumé statistique pour cette colonne
      print(summary(dataset[[col]]))
    } # Ici nous sortons de la condition (niveau 3)
  } # Ici nous sortons de la boucle (niveau 2)
}# Ici nous sortons de la fonction (niveau 1)
  1. Adopter une structure globale pour vos scripts : un code R peut être comparé à une recette de cuisine. Si tous les éléments sont dans le désordre et sans structure globale, la recette risque d’être très difficile à suivre. Cette structure risque de changer quelque peu en fonction de la recette ou de l’auteur(e), mais les principaux éléments restent les mêmes. Dans un code R, nous pouvons distinguer plusieurs éléments récurrents que nous vous recommandons d’organiser de la façon suivante :
  1. Charger les différents packages utilisés par le script. Cela permet dès le début du code de savoir quelles sont les fonctions et méthodes qui seront employées dans le script. Cela limite aussi les risques d’oublier des packages qui seraient chargés plus loin dans le code.
  2. Définir les fonctions dont vous aurez besoin en plus de celles présentes dans les packages. Idem, placer nos fonctions en début de code évite d’oublier de les charger ou de les chercher quand nous en avons besoin.
  3. Définir le répertoire de travail avec la fonction setwd et charger les données nécessaires.
  4. Effectuer au besoin les opérations de manipulation sur les données.
  5. Effectuer les analyses nécessaires en scindant si possible les différentes étapes. Notez également que l’étape de définition des fonctions complémentaires peut être effectuée dans une feuille de code séparée, et l’ensemble de ces fonctions chargées à l’aide de la fonction source. De même, si la manipulation des données est conséquente, il est recommandé de l’effectuer avec un code à part, d’enregistrer les données structurées, puis de les charger directement au début de votre code dédié à l’analyse.
  1. Exploiter les commentaires délimitant les sections dans RStudio : il est possible d’écrire des commentaires d’une certaine façon pour que l’IDE les détecte comme des délimiteurs de sections. L’intérêt principal est que nous pouvons ensuite facilement naviguer entre ces sections en utilisant RStudio comme montré à la figure 1.18, mais aussi masquer des sections afin de faciliter la lecture du reste du code. Pour délimiter une section, il suffit d’ajouter une ligne de commentaire comprenant quatre fois les caractères -, = ou # à la suite :

# Voici ma section 1 ----------------------------------

# Voici ma section 2 ==================================

# Voici ma section 3 ##################################

# Autre exemple pour mieux marquer la rupture dans un code : 

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#### Titre de ma section 4 ####
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Navigation dans des sections de codes avec RStudio

Figure 1.18: Navigation dans des sections de codes avec RStudio

  1. Adopter une structure globale pour vos projets : au-delà du script, il est nécessaire de bien structurer vos projets, le plus important étant d’utiliser une structure commune à chaque projet pour vous faciliter le travail. Nous proposons à la figure 1.19 un exemple de structure assez générale pouvant être utilisée dans la plupart des cas. Elle sépare notamment les données originales des données structurées, ainsi que les fonctions complémentaires et la structuration des données du principal bloc d’analyse.
Structure de dossier recommandée pour un projet avec R

Figure 1.19: Structure de dossier recommandée pour un projet avec R

Ne négligez jamais l’importance d’un code bien écrit et documenté !