- Du bon sens ..
- Organisation d'un projet
- Documentation des Fonctions avec roxygen2
- Gestion des Paquets
- Manipulation et Analyse des Données
- Packages classiques
- Tests et Validation
- Collaborer avec Git et GitHub
- Coder en anglais! -> Pour éviter les charactères spéciaux
- Choisir une police! ->
snake_case
oucamelCase
- Espacer le code -> Faites respirer votre code ! Aller à la ligne pour améliorer la lisibilité
- Choisissez un nom de variable cohérent -> On oublie les raccourcis, les abbréviations. Mieux vaut un nom long qu'un raccourci incompréhensible.
- 1 fonction = 1 action -> On splitte le code le plus possible en fonction pour le rendre lisible et maintenable !
- Pas de commentaire inutle -> Les commentaires doivent apporter qqch, inutile de garder du code commenté ! Un code bien fait, n'a pas besoin de commentaire intempestif !
- Pas de harcode ! -> Il génère des bugs, il empêche une bonne lecture du code, il empêche un débugage correcte, et en plus souvent on y trouve des mots de passe !!
- Utiliser un formatteur de code -> Permet d'améliorer l'homogénéité du code et le rendre lisible.
Le package
styler
permet de formatter du code R.
Pour stocker des variables sensibles on pourra utiliser le fichier
.Renviron
et faire appelle aux différentes variables via unSys.getenv('variable_name')
Pour un projet de datascience on s'inspirera de l'architecture suivante :
project_name
├─ README.md # A markdown file that provides an overview of the project, including how to set it up, use it, and any other relevant information.
├─ data # Directory for storing datasets used in the project.
│ ├─ external # Subdirectory for storing external data sources that are imported into the project.
│ └─ raw # Subdirectory for storing raw data that hasn't been processed yet.
├─ docs # Directory for documentation files, which may include detailed explanations, tutorials, and other project-related documents.
├─ results # Directory for storing results generated by the project.
│ └─ user # Subdirectory for user-specific results or outputs.
└─ <package_name> # Directory for source code and scripts.
├─ DESCRIPTION # A file describing the project, its purpose, and other metadata. Used in R projects for package information.
├─ NAMESPACE # A file that defines the functions and objects that are exported by the package and those that are imported from other packages.
├─ man # Subdirectory for R docstring, accessed by ?<name_function>
└─ R # Subdirectory for R scripts containing functions, classes, and other R code.
Le package devtools
permet de gérer tout le développement d'un package.
# Pour créer un package R from scratch
devtools::create("path/to/package_name")
# Pour générer la documentation
# Il faut d'abord avoir rédiger la docstring correctement
devtools::document("path/to/package_name")
# Construire la documentation technique du package en PDF
devtools::build_manual("path/to/package_name")
# Construire l'archive du package
devtools::build("path/to/package_name")
# Pour ajouter des dépendances à votre package
usethis::use_package('dependency_name')
# Pour run tous les tests unitaires
devtools::test()
# Pour développer le package en chargeant toutes les fonctions :
devtools::load_all("path/to/package_name")
- Utiliser roxygen2 pour documenter les fonctions :
#' Calculate the mean of a numeric vector
#'
#' This function takes a numeric vector as input and returns the mean
#' of the values in the vector. If the vector is empty or contains only NA values,
#' the function returns NA.
#'
#' @param x (numerical vector)
#' @param na.rm (boolean) Indicating whether NA values should be removed
#' before calculation. Defaults to FALSE.
#' @return (float | NA) The mean of the numeric vector. If the vector is empty or contains
#' only NA values, NA is returned.
#' @examples
#' calculate_mean(c(1, 2, 3, 4, 5))
#' calculate_mean(c(1, 2, NA, 4, 5), na.rm = TRUE)
#' calculate_mean(c(NA, NA, NA))
#' @export
calculate_mean <- function(x, na.rm = FALSE) {
# Check if input is a numeric vector
if (!is.numeric(x)) {
stop("Input must be a numeric vector")
}
result <- mean(x, na.rm = na.rm)
return(result)
}
Le @export est indispensable pour rendre la fonction accessible une fois le package chargé par l'utilisateur.
devtools::install('<path_to_project>') # for a project/repo
install.packages('<lib_name>') # for a CRAN available library
install.packages('<path_to_archive>') # for a tar.gz archive for example
Pour ne pas avoir des interférences et soucis de compatabilités entre plusieurs projets. On utilisera
renv
. L'outil de gestion des environnements virtuels sur R.
- Il existe 3 formats de tableaux :
data.frame
-> librarie de basetibble
-> syntaxe la plus claire et lisible. Fais partie de l'écosystèmedplyr
,tidyverse
data.table
-> La librairie la plus rapide et de très loin. Parfaite pour de très gros volume de données
Utilisez tout sauf data.frame
qui a une syntaxe proche de pandas certes mais et avec de pauvres performances.
Notez qu'il y des porosités entre les packages mais impliquent des changements de type de tableaux et une clarté appauvrie de la technologie utilisée !
Pour modifier le tableau en place et ne pas le réaffecter, on peut utiliser
%<>%
du packagemagrittr
. Cela fonctionne pour n'importe quel autre type de variable. Voir ici pour plus d'infos.
Exemple :
# Avec tibble / dplyr
df = df %>%
select(product_id, sales) %>%
filter(sales > 200) %>%
mutate(sales_tax = sales * 0.1) %>%
group_by(product_name) %>%
summarise(total_sales = sum(sales))
# Avec data.table
dt <- dt[, .(product_id, sales)] %>%
.[sales > 200] %>%
.[, sales_tax := sales * 0.1] %>%
.[, .(total_sales = sum(sales)), by = product_name]
PS : L'opérateur
:=
pour déclarer une nouvelle colonne dans un tableaudata.table
affecte le tableau initial. Il ne retourne pas un nouvel objet.
Le soucis de ces syntaxes est que les noms des colonnes sont d'offices hardcodés et ne sont pas sous forme de variable. Pour se faire, on pourra utiliser
!!sym(var)
avecdplyr
et/ouget(var)
/eval(var)
avecdata.table
- DataScience :
dplyr
dans l'écosystèmetidyverse
,data.table
- Basde de données :
DBI
- Graphiques :
plotly
,ggplot2
- Date :
lubridate
- Formattage de string :
glue
- Parallèlisation :
foreach
,parallel
- Dashboard : l'écosystème de
shiny
- Operateur Pipes :
magrittr
- R Orienté Objet :
R6
- Calcul scientifique :
MASS
,zoo
,mgcv
- Écrire des tests unitaires avec testthat :
library(testthat)
library(package_name)
test_that("add_numbers works correctly", {
expect_equal(add_numbers(1, 2), 3)
expect_equal(add_numbers(-1, -2), -3)
expect_equal(add_numbers(0, 0), 0)
expect_error(add_numbers("a", "b"), "non-numeric argument")
})
- Structurer les tests dans un projet.
L'utilisation de Git et GitHub est essentielle pour collaborer efficacement sur des projets de développement en R. Voici quelques bonnes pratiques pour gérer la version de votre code et collaborer avec votre équipe.
Git est petit logiciel qui permet de sauvegarder du code, tracer les modifications, gérer différentes modifications en même temps. Il est INDISPENSABLE dans le cycle de vie de n'importe quel projet de code.
-
Initialiser un dépôt Git :
git init
-
Cloner un dépot existant
git clone <url_du_dépôt>
-
Création d'une branche de travail et se positioner dessus
git branch <branch> # Création git checkout <branch> # Se positionner dessus
-
Ajouter des modifications pour une potentielle future sauvegarde
git add <fichier_ou_dossier>
-
Sauvegarder les changements
git commit -m "Message du commit"
-
Les sauvegarder sur le serveur
git pull origin <branche>
-
Les récupérer depuis le serveur
git pull origin <branche>
-
Fusionner deux branches
On peut le faire après avoir push toutes les modifications sur le serveur, puis faire le
merge
depuis l'IHM de gitlab.Sinon en local :
git merge <branch1> <branch2>
Il existe une extension git sur Rstudio lors de la création d'un Rprojet.
Chaque branche est parfaitement indépendante du reste. On peut donc y faire ce qu'on veut sans influence sur les autres travaux. On veillera donc à supprimer les parties du code qui nous interesse pas