Chapitre 1 Construire un package
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 packages1 dâHadley Wickham & Jennifer Bryan, disponible en ligne.
1.1 Initialiser un package
Une maniÚre simple, et intégrée à RStudio
, pour initialiser un package est dâexecuter les Ă©tapes suivantes :
đ Ă vous de jouer (dĂ©jĂ )!
créer un nouveau projet (menu déroulant en haut à gauche dans RStudio)
choisir âNew Directoryâ
choisir âR package using devtoolsâ (sâil nâest pas disponible câest que le package
devtools
nâest pas installer et dans ce cas on peut alors choisir âR packageâ â la diffĂ©rence Ă©tant quâavec âR packageâ, il faudra supprimer des fichiers crĂ©Ă©s automatiquement mais inutiles)donner un nom au package, par exemple
mypkgr
.
On récupÚre alors la structure minimale pour un package , à savoir :
un fichier DESCRIPTION dont les parties
Title
,Version
,Authors@R
etDescription
sont Ă Ă©diter (dâautres parties pourront ĂȘtre Ă©diter voire mĂȘme ajouter de maniĂšre automatique, comme nous le verrons plus loin)un fichier NAMESPACE qui sera Ă©ditĂ© automatiquement ultĂ©rieurement
un dossier R/ dans lequel on va ajouter des fichiers de scripts
.R
devtools
ajoute Ă©galement trois fichiers facultatifs :
.gitignore, relatif Ă
git
, outils de contrÎle de version que nous verrons en détails dans la partie suivante surgit
& GitHubmypkgr.Rproj qui est un fichier spécifique de RStudio, et permet de définirles 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 fichier
mypkgr.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 \(\boldsymbol \mu\) dans \(\mathbb{R}^p\) et matrice de variance-covariance \(\boldsymbol\Sigma\) dâordre de \(p\) quelconques), et on souhaite pouvoir calculer toutes les valeurs de la densitĂ© Ă©valuĂ©es sur les \(n\) points \(\mathbf{x}\) en un seul appel de la fonction.
Pour rappel, la fonction de densitĂ© dâune loi normale multivariĂ©e sâĂ©crit : \[\displaystyle (2\pi )^{-p/2}\det({\boldsymbol {\Sigma }})^{-1/2}\,\exp \left(-{\frac {1}{2}}(\mathbf {x} -{\boldsymbol {\mu }})^{\mathsf {T}}{\boldsymbol {\Sigma }}^{-1}(\mathbf {x} -{\boldsymbol {\mu }})\right)\]
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.
đ Ă vous de jouer !
Voici une proposition de fonction que vous pouvez tĂ©lĂ©charger ici. â ïž ATTENTION ! Si vous cliquez trop vite sur le lien ci-dessous, cela invalidera votre participation Ă la formation !
Pour des conseils lors de la rédaction de code, voir le chapitre R code dans R packages (2023) de Wickham & Bryan2.
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.
đ Ă 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 :
usethis::use_package_doc()
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
Re-charger le package
Ctrl+Shift+L
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, executer la commande suivante :
usethis::use_testthat()
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 contenant 2 tests qui devrait sâappeller test-mvnpdf.R
Ă mettre dans le dossier testthat/
(plutĂŽt que de le crĂ©er vous-mĂȘme, vous pouvez simplement utiliser la fonction usethis::use_test()
qui créera le fichier pour vous en le plaçant directement au bon endroit) :
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)))
})
test_that("correct results for bivariate gaussian", {
expect_equal(mvnpdf(x=matrix(rep(1.96,2), nrow=2, ncol=1), Log=FALSE)$y,
mvtnorm::dmvnorm(rep(1.96, 2)))
})
Pour exĂ©cuter ces tests, on peut utiliser âTest packageâ (Ctrl+Shift+T
) du menu âMoreâ dans lâonglet âBuildâ, ou alors executer devtools::test()
dans la console.
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 identifiĂ© 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 et fonctionne comme attendu, afin que l package puisse sâinstaller sans problĂšme sur diffĂ©rents systĂšmes dâexploitation. Il est impĂ©ratif de âpasserâ le R CMD CHECK
pour pouvoir déposer un package sur le CRAN.
Pour exĂ©cuter celui-ci, utiliser âCheckâ (Ctrl+Shift+E
) dans lâonglet âBuildâ, ou alors executez devtools::check()
dans la console.
Lors du R CMD 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â Ctrl+Shift+B
dans lâonglet âBuildâ (devtools::install()
ou ).
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â juste Ă cĂŽtĂ© de âGenerate documentation with Roxygenâ puis cocher la case âInstall and Restartâ.
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)
plot.mvnpdf <- function(x, ...) {
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.
Annexe 1.2 : soumettre son package au CRAN
Executer les 2 commandes suivantes : devtools::check()
puis devtools::submit_cran()
.
Pour plus de détails, voir la procédure recommandée dans Wickham & Bryan (2023)3