Chapitre 1 Construire un package R
Nous présentons ici comment construire un package efficacement à l’aide d’outils
graphiques présents dans Rstudio et du package devtools
.
Le support de référence sur ce sujet est le livre R packages d’Hadley Wickham.
1.1 Initialiser un package
Une manière simple, et intégrée à Rstudio, pour initialiser un package est :
de créer un nouveau projet (menu déroulant en haut à droite dans Rstudio)
choisir “New Directory”
choisir “R package using devtools” (s’il n’est pas disponible, choisir “R package”, différence étant qu’avec “R package”, il faudra supprimé des fichiers créés automatiquement mais non utiles)
donner un nom au package, par exemple
mypkgr
On récupère la structure minimale pour un package R, à savoir :
un fichier
DESCRIPTION
dont les partiesTitle
,Version
,Authors@R
etDescription
sont à éditer (d’autres parties pourront être éditer voire même ajouter de manière automatique, voir plus loin)un fichier
NAMESPACE
qui sera éditer automatiquement plus loinun dossier
R
dans lequel on va ajouter des fichiers de scripts R
Rstudio ajoute également trois fichiers facultatifs :
.gitignore
, relatif àgit
, outils de contrôle de version que nous verrons en détails dans la partie sur GitHubmypkgr.Rproj
qui est un fichier spécifique de Rstudio, et permet de définir les caractéristiques et préférences du projet que nous venons de créer.Rbuildignore
qui permet d’ignorer certains fichiers au moment où on construira le package un peu plus loin (par exemple, le fichiermypkgr.Rproj
ne doit pas être inclus dans le package)
1.2 Ajouter une fonction : exemple fil rouge
Nous vous proposons de coder la fonction suivante, que nous reprendrons tout au long de la formation :
Nous souhaitons calculer la valeur de la densité d’une loi normale multivariée sur \(\mathbb{R}^p\) en \(n\) points. Notre fonction doit pouvoir s’appliquer pour n’importe quelle loi normale multivariée (vecteur de moyennes dans \(\mathbb{R}^p\) et matrice de variance-covariance d’ordre de \(p\) quelconques), et on souhaite pouvoir calculer toutes les valeurs de la densité évaluées sur les \(n\) points en un seul appel de la fonction.
Vous devez donc créer une fonction mvnpdf()
dans un fichier nommé mvnpdf.R
dans le dossier R
du package, qui :
prend en arguments :
x
une matrice, à \(n\) colonnes (les observations) et \(p\) lignesmean
un vecteur de moyennesvarcovM
une matrice de variance-covarianceLog
un paramètre logique valantTRUE
par défaut
renvoie une liste contenant la matrice
x
ainsi qu’un vecteur des images des points dex
par la fonction de densité de la variable aléatoire de loi normale multivariée considérée.
A vous de jouer !
ATTENTION ! Si vous cliquez trop vite sur le lien ci-dessous, cela invalidera votre participation à la formation !
Voici une proposition de fonction que vous pouvez télécharger ici.
Pour des conseils lors de la rédaction de code, voir la page R code du site d’Hadley.
1.3 Documenter une fonction
Il est important de bien documenter votre code. Tout projet a au moins 2 développeurs :
vous
vous dans 6 mois
Par égard à votre futur-vous, soyez sympas et prenez le temps de documenter votre code !
Nous vous conseillons vivement d’utiliser le package roxygen2
pour documenter
vos packages. L’avantage principal étant d’avoir l’aide d’une fonction dans
le même fichier que le code définissant cette fonction.
A vous de jouer !
Commencer par insérer le squelette de l’aide grâce à “Insert Roxygen Skeleton” situé dans le menu “Code” ou le sous-menu Baguette magique dans la fenêtre de script.
Compléter la documentation en renseignant :
le titre de la fonction (première ligne)
la description de ce que fait la fonction (deuxième paragraphe)
si vous renseignez un troisième paragraphe, cette partie ira dans la section “Details” de la page d’aide
la signification des paramètres
la sortie, après la balise
@return
Générer la documentation à l’aide de “Document” dans le menu “More” de l’onglet “Build” (ou Ctrl+Shift+D ou
devtools::document()
). L’effet de cette commande est multiple :
un dossier
man
a été créé et à l’intérieur, un fichiermvnpdf.Rd
a été créé et contient les informations de l’aide de la fonctionle fichier
NAMESPACE
a été modifié
En cas de bug ou par curiosité ET une fois que vous avez terminé vous pouvez consulter cette proposition.
Pour plus de détails sur la documentation de package et les balises
roxygen2
, voir la page
Object documentation du site d’Hadley.
Finissons par évoquer une fonction du package usethis
qui initialise une
page d’aide pour le package dans son ensemble :
::use_package_doc() usethis
La page d’aide générée sera alors accessible, une fois le package installé, via :
?mypkgr
1.4 Tester le package de manière intéractive
Pour tester le package, vous devez le charger dans R à l’aide de :
dans l’onglet “Build”, le menu “More” puis “Load All” (ou Ctrl+Shift+L ou
devtools::load_all()
).
Vous pouvez alors utiliser votre package directement dans R : consulter
l’aide de la fonction avec ?mvnpdf
et par exemple exécuter les commandes renseignées dans la section exemple de cette page d’aide.
?mvndpf
Ainsi, lors du développement, vous pouvez :
Ajouter/Modifier le code R
Re-charger le package Ctrl+Shift+L
Essayer dans la console
Et ainsi de suite…
1.5 Tester le package de manière automatique
Pour initialiser la fonctionnalité de tests automatiques dans le package, utiliser :
::use_testthat() usethis
Cette commande induit la création d’un dossier tests
qui comprend un fichier testthat.R
- à ne pas modifier - et un dossier testthat
dans lequel on va insérer nos tests. Cet outils s’appuie sur la théorie des tests unitaires.
Voici par exemple, le contenu d’un fichier qu’on appellera test-univariate.R
à mettre dans le dossier testthat
:
test_that("correct result for univariate gaussian", {
expect_equal(mvnpdf(x=matrix(1.96), Log=FALSE)$y, dnorm(1.96))
expect_equal(mvnpdf(x=matrix(c(1.96, -0.5), ncol = 2), Log=FALSE)$y,
dnorm(c(1.96, -0.5)))
})
Et un deuxième, appelé test-bivariate.R
:
test_that("correct results for bivariate gaussian", {
expect_equal(mvnpdf(x=matrix(rep(1.96,2), nrow=2, ncol=1), Log=FALSE)$y,
::dmvnorm(rep(1.96, 2)))
mvtnorm })
Pour exécuter ces tests, on peut utiliser dans l’onglet “Build”, le menu
“More”, “Test package” (ou devtools::test()
ou Ctrl+Shift+T).
L’avantage de ces tests automatiques est qu’ils vont s’exécuter à chaque fois qu’on effectuera un check du package.
Une bonne pratique est d’ajouter un test unitaire à chaque fois qu’un bug est identifier et résolu, afin de pouvoir immédiatement identifier et prévenir qu’une erreur identique ne se reproduise dans le futur.
1.6 Faire un check du package
Faire un check signifie vérifier que tout est correct dans le package. Il est nécessaire de “passer” le check pour pouvoir déposer le package sur le CRAN.
Pour exécuter celui-ci, utiliser “Check” dans l’onglet “Build” (devtools::check()
ou Ctrl+Shift+E).
Lors du check, les tests que nous avons mis au point précédemment sont exécutées. C’est justement l’avantage d’avoir fait ces tests, nous n’avons plus besoin de s’en préoccuper, mais juste de réagir en cas d’erreurs renvoyées.
1.7 Installer le package
Pour le moment, le package n’existe que dans l’environnement associé au projet Rstudio qu’on a créé. Pour pouvoir l’utiliser dans R de manière générale, il faut l’installer (comme un package du CRAN par exemple).
Pour faire ça, utiliser “Install and Restart” dans l’onglet “Build” (devtools::install()
ou Ctrl+Shift+B).
Et enfin, vous pouvez configurer le comportement de Rstudio pour qu’au moment de l’installation, il documente en même temps le package : aller dans l’onglet “Build”, le menu “More” puis “Configure Build Tools”. Cliquer ensuite sur “Configure” puis cocher la case en bas “Install and Restart”.
1.8 Annexe 1.1 : ajouter une méthode S3
Dans la plupart des packages on est amenés à implémenter des méthodes S3,
très souvent pour qu’à partir d’un objet résultat res
, on puisse exécuter
print(res)
, summary(res)
, plot(res)
…
Voici un exemple de méthode plot()
qu’on peut ajouter dans notre package :
#' Plot of the mvnpdf function
#'
#' @param x an object of class \code{mvnpdf} resulting from a call of
#' \code{mnvpdf()} function.
#' @param ... graphical parameters passed to \code{plot()} function.
#'
#' @return Nothing is returned, only a plot is given.
#' @export
#'
#' @examples
#' pdfvalues <- mvnpdf(x=matrix(seq(-3, 3, by = 0.1), nrow = 1), Log=FALSE)
#' plot(pdfvalues)
<- function(x, ...) {
plot.mvnpdf plot(x$x, x$y, type = "l", ...)
}
Attention ! Pour que cette méthode fasse bien ce qu’on veut quand on
l’applique au résultat de notre fonction mvnpdf()
, il faut déclarer que
ce résultat est de classe mvnpdf
.
Tester cette fonction, en exécutant l’exemple.
N’oubliez pas de réinstaller le package (“Install and Restart” ou Ctrl+Shift+B).
Consulter le contenu du dossier man
et les modifications qui ont été
apportées au fichier NAMESPACE
.
Voici une proposition de solution : le
fichier
contient le code complet
de la fonction mvnpdf()
et de la méthode plot()
associée.