Packages R - Département de mathématiques et de statistique
Transcription
Packages R - Département de mathématiques et de statistique
Packages R Sophie Baillargeon, Université Laval 26 mars 2015 Contents Utilisation de packages R 2 Installation et chargement d’un package R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Différentes façons d’installer un package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Accéder au contenu d’un package R chargé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Fonctions publiques versus privées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Jeux de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Code source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Création de packages R 8 Étape 1. Écrire les fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Étape 2. Créer la bonne structure de fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Dossier nommé “R” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Dossier nommé “man” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Fichier nommé “DESCRIPTION” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Fichier nommé “NAMESPACE” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Autres fichiers et dossiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Étape 3. Écrire la Documentation des fonctions et du package . . . . . . . . . . . . . . . . . . . . 10 Comment écrire de la documentation avec roxygen2? . . . . . . . . . . . . . . . . . . . . . . 11 Comment générer les fichiers .Rd et le fichier NAMESPACE ? . . . . . . . . . . . . . . . . . . 14 Étape 4. Compiler et vérifier le package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Sous-étape a) Créer un projet RStudio avec notre package . . . . . . . . . . . . . . . . . . . . 14 Sous-étape b) Configurer les options de RStudio . . . . . . . . . . . . . . . . . . . . . . . . . 14 Sous-étape c) Compiler à partir du menu Build de RStudio . . . . . . . . . . . . . . . . . . . 15 Étape 5. Au besoin, mettre à jour le package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Références 16 1 Utilisation de packages R Lors de l’ouverture d’une session R, nous avons accès à un bon nombre de fonctions et de jeux de données. Ces objets R sont accessibles, car ils proviennent de packages R chargés automatiquement à l’ouverture de session. Un package R est simplement un regroupement de fonctions et de données documentées. Installation et chargement d’un package R Il est simple de charger en R des packages supplémentaires à ceux chargés par défaut. Il suffit d’utiliser la commande library comme dans cet exemple : library(ggplot2) Cette commande fonctionne uniquement si le package a été préalablement installé sur notre ordinateur. L’installation d’un package et le chargement d’un package sont donc deux étapes distinctes. L’installation n’a pas à être faite à chaque fois que le package est chargé. On doit la faire la première fois que l’on souhaite utiliser le package, puis à chaque fois que l’on met R à jour. Tout comme le logiciel R, les packages sont périodiquement mis à jour par leurs auteurs. On désirera donc parfois les réinstaller afin de les mettre à jour. En RStudio, il est facile de voir la liste des packages installés sur son ordinateur pour la version de R utilisée. On retrouve cette liste dans la sous-fenêtre Packages. Différentes façons d’installer un package L’installation de package a déjà été abordée dans le Guide d’installation ou de mise à jour de R et RStudio. Voici de l’information plus détaillée à ce sujet. À partir du CRAN : Le CRAN est le dépôt informatique de packages géré par le R core team. C’est là que la majorité des packages R sont rendus disponibles publiquement. Pour installer un package à partir d’un des miroirs du CRAN, on utilise la fonction install.packages comme dans cet exemple : install.packages("ggplot2") Cette commande lance le téléchargement du fichier compressé d’installation du package, puis lance la décompression du fichier dans le dossier approprié. Bien sûr, il faut être connecté à internet pour que la commande fonctionne. La version du package correspondant à notre système d’exploitation est automatiquement sélectionnée : • .tar.gz (package source) pour Linux/Unix, • .zip pour Windows, • .tgz pour OS X (Mac). Aussi, install.packages télécharge et installe par défaut les packages dont dépend le package qui nous intéresse. Cette option est très pratique, car certains packages dépendent d’un grand nombre de packages (ggplot2 en est un bon exemple). RStudio offre une fonctionnalité pour rendre encore plus conviviale l’installation de packages. Dans la sous-fenêtre Packages, le bouton Install (en haut à gauche) permet d’installer des packages. En fait, cette fonctionnalité ne fait qu’écrire et soumettre la commande install.packages en fonction des options choisies par l’utilisateur. 2 À partir d’un fichier compressé d’installation : Afin d’installer un package non publicisé, qui n’est pas téléchargeable sur le web, on doit avoir sur notre ordinateur le fichier compressé d’installation du package correspondant à notre système d’exploitation (ou le package source). On installe le package avec la commande install.packages comme dans cet exemple : install.packages("C:/R/coursR/ggplot2_1.0.1.zip", repos = NULL) On peut aussi utiliser cette façon de faire si on télécharge manuellement le fichier compressé d’installation du package, par exemple à partir du site web personnel de l’auteur du package. Cette technique est aussi utile lorsque nous avons besoin d’une ancienne version d’un package. Si on laisse install.packages télécharger du CRAN un package, il téléchargera la dernière version du package. Parfois, des mises à jour de package rendent certains de nos programmes non fonctionnels et on souhaite continuer d’utiliser une version antérieure du package. Pour installer une version d’un package qui n’est pas sa dernière version, il faut aller sur sa page web du CRAN (par exemple http://CRAN.R-project.org/package=ggplot2), et aller télécharger manuellement la version dont on a besoin dans Old Sources. Ce type d’installation peut se réaliser par le menu Install de la sous-fenêtre Packages de RStudio, en sélectionnant : Install from: -> Package Archive File. À partir d’un dépôt informatique autre que le CRAN : En plus du CRAN, on retrouve des packages R à d’autres endroits sur le web, notamment sur : • le dépôt informatique de packages en bio-informatique Bioconductor : des instructions d’installation sont disponibles sur la page web : http://www.bioconductor.org/install/, • un service wed d’hébergement et de gestion de développement de logiciels tel que Github ou Bitbucket : le package R devtools offre des fonctions pour télécharger et installer directement à partir de ces sites (ex. fonctions install_github et install_bitbucket). Accéder au contenu d’un package R chargé Une fois un package chargé en R avec la commande library, on peut accéder à son contenu dans la session R. On a vu dans le cours sur les calculs statistiques et mathématiques en R comment fonctionne l’évaluation d’expressions en R. On sait donc que le chargement d’un nouveau package ajoute un environnement dans le chemin de recherche de R, juste en dessous de l’environnement de travail. Cet environnement contient les fonctions publiques et les données du package. Fonctions publiques versus privées Dans la phrase précédente, le mot publiques n’est pas anodin. Les fonctions publiques d’un package sont celles destinées à être appelées par des utilisateurs. Un package peut aussi contenir des fonctions privées (ou internes, ou cachées) qui sont uniquement destinées à être appelées par d’autres fonctions du package. Les fonctions privées sont très utiles pour partitionner du code en bloc de calculs indépendants. Elles sont principalement utiles pour éviter de répéter des bouts de code. Si un calcul doit être exécuté fréquemment par les fonctions d’un package, le développeur peut choisir de répéter un même bout de code pour ce calcul aux endroits appropriés dans le code source. Cependant, la présence de bouts de code identiques dans un programme est une mauvaise pratique de programmation. Si on a besoin de modifier le calcul fait dans ces bouts de code, il faut penser à aller faire les modifications à tous les endroits où le code est répété. Il est risqué d’oublier de modifier un des bouts. Si au contraire, on a créé une fonction pour faire le calcul, la modification doit être faite à un seul endroit. On gagne du temps à long terme, le code est plus clair et on minimise les risques d’erreur. En informatique, on appelle ce principe Don’t Repeat Yourself . Appliquer ce principe est une bonne pratique de programmation. 3 Environnement d’un package dans le chemin de recherche : On peut lister le contenu de l’environnement ajouté dans le chemin de recherche de R lors du chargement d’un package avec la fonction ls comme dans l’exemple suivant : ls("package:stats") ## [1] "acf" "acf2AR" ## [4] "add1" "addmargins" ## [7] "aggregate.data.frame" "aggregate.ts" "add.scope" "aggregate" "AIC" Seulement les 9 premiers éléments de la liste sont affichés ici, car cette liste compte en réalité 446 éléments. Espace de noms (namespace) d’un package : Il est aussi possible de lister tout le contenu d’un package, public ou privé, grâce à la fonction getNamespace, comme dans l’exemple suivant ls(getNamespace("stats")) ## [1] "[.acf" ## [5] "[.tskernel" "[.formula" "[.terms" "[[.dendrogram" "[<-.ts" "[.ts" "acf" Seulement les 8 premiers éléments de la liste sont affichés ici, car cette liste compte en réalité 1091 éléments. Cet environnement, où tout le contenu d’un package est présent, se nomme espace de noms (en anglais namespace). L’espace de nom n’est pas dans le chemin de recherche de R, mais son contenu est tout de même accessible grâce à l’opérateur ::: et à des fonctions telles que getAnywhere et getS3method. Par exemple, le package stats contient la fonction privée Tr qui permet de calculer la trace d’une matrice. Il n’est pas possible d’accéder directement à cette fonction, c’est-à-dire à partir du chemin de recherche. Tr ## Error in eval(expr, envir, enclos): objet 'Tr' introuvable On arrive cependant à y accéder par les commandes suivantes : stats:::Tr ## ## ## ## function (matrix) sum(diag(matrix)) <bytecode: 0x00000000062e4dc0> <environment: namespace:stats> getAnywhere(Tr) ## ## ## ## ## ## ## ## ## A single object matching 'Tr' was found It was found in the following places namespace:stats with value function (matrix) sum(diag(matrix)) <bytecode: 0x00000000062e4dc0> <environment: namespace:stats> 4 Aussi la méthode S3 pour la fonction générique plot fait partie du package stats, mais elle n’est pas publique. plot.lm ## Error in eval(expr, envir, enclos): objet 'plot.lm' introuvable On peut tout de même y accéder avec la fonction getS3method args(getS3method("plot", "lm")) ## function (x, which = c(1L:3L, 5L), caption = list("Residuals vs Fitted", ## "Normal Q-Q", "Scale-Location", "Cook's distance", "Residuals vs Leverage", ## expression("Cook's dist vs Leverage " * h[ii]/(1 - h[ii]))), ## panel = if (add.smooth) panel.smooth else points, sub.caption = NULL, ## main = "", ask = prod(par("mfcol")) < length(which) && dev.interactive(), ## ..., id.n = 3, labels.id = names(residuals(x)), cex.id = 0.75, ## qqline = TRUE, cook.levels = c(0.5, 1), add.smooth = getOption("add.smooth"), ## label.pos = c(4, 2), cex.caption = 1) ## NULL On aurait aussi pu y accéder avec ::: ou getAnywhere. Environnement englobant des fonctions d’un package : Dans le cours Création de fonctions en R, le sujet de l’exécution d’une fonction est abordé. On y parle d’environnement englobant, qui permet de déterminer le chemin de recherche utilisé lors de l’exécution d’une fonction. Quel est l’environnement englobant des fonctions d’un package? Il s’agit de l’espace de noms du package, comme en fait foi l’exemple suivant. environment(var) ## <environment: namespace:stats> C’est pour cette raison que les fonctions d’un package peuvent accéder directement aux fonctions internes du package. Donc, dans le code source d’un package, on n’a pas besoin d’utiliser ::: ou getAnywhere pour utiliser des fonctions internes. Le chemin de recherche complet lors de l’exécution d’une fonction dans un package chargé est le suivant : 1. 2. 3. 4. 5. 6. l’environnement local d’exécution de la fonction, l’environnement englobant de la fonction, soit l’espace de noms du package, l’environnement des objets importés par le package, l’environnement du package R de base, l’environnement de travail, les environnements de tous les packages chargés. Ce chemin va nous aider à déterminer quels objets R peuvent être utilisés dans le corps de fonctions incluses dans un package que l’on crée (vu plus loin). Un des environnements de cette liste n’a jamais été mentionné auparavant : l’environnement des objets importés par le package. Il s’agit de la liste des fonctions ne provenant pas directement du package, ou encore du package R de base, qui sont utilisées dans le package. 5 Jeux de données Parfois, les jeux de données inclus dans un package se retrouvent directement dans l’environnement d’un package dans le chemin de recherche. C’est le cas par exemple des jeux de données du package datasets. ls("package:datasets") ## [1] "ability.cov" ## [5] "anscombe" "airmiles" "attenu" "AirPassengers" "airquality" "attitude" "austres" Seulement les 8 premiers éléments de la liste sont affichés ici, car cette liste compte en réalité 103 éléments. Cependant, les jeux de données sont parfois cachés. Ils sont traités différemment des fonctions privées et ne se retrouvent même pas dans l’espace de noms du package. C’est le cas par exemple dans le package copula. library(copula) La fonction data est très utile dans ce cas. Cette fonction a plusieurs utilités. Premièrement, elle permet d’énumérer tous les jeux de données contenus dans un package. data(package = "copula") Le résultat est affiché dans une fenêtre indépendante, pas dans la console. On apprend que le pacakge copula contient un jeu de données nommé uranium. Cependant, ce jeu de données est caché et on ne peut pas y accéder directement. str(uranium) ## Error in str(uranium): objet 'uranium' introuvable La fonction data permet alors de charger le jeu de données dans notre environnement de travail. data(uranium) str(uranium) ## 'data.frame': 655 obs. of 7 variables: ## $ U : num 0.544 0.591 0.531 0.633 0.568 ... ## $ Li: num 1.57 1.34 1.41 1.34 1.2 ... ## $ Co: num 1.03 1.17 1.01 1.06 1.01 ... ## $ K : num 4.21 4.34 4.22 4.16 4.22 ... ## $ Cs: num 1.66 1.92 1.85 1.85 1.73 ... ## $ Sc: num 0.839 0.934 0.903 0.908 0.763 ... ## $ Ti: num 3.57 3.38 3.7 3.66 3.44 ... Cette pratique de cacher les jeux de données d’un package tend à disparaître. 6 Documentation Tout package doit obligatoirement contenir de la documentation sous forme de fiches d’aide. Ces fiches d’aide s’ouvrent avec la fonction help ou l’opérateur ? lorsque l’on connaît le nom de la fonction pour laquelle on veut afficher la documentation. Les éléments suivants sont toujours documentés dans une fiche d’aide : • • • • les fonctions publiques, les méthodes pour des fonctions génériques, les jeux de données, le package lui-même. Une fiche d’aide peut servir à documenter plus d’un élément (par exemple un groupe de fonctions similaires). On ouvrir toute la documentation d’un package en passant par : help.start() -> Packages -> nom du package. On a ainsi accès aux fiches d’aide, mais aussi à un fichier descriptif du package, parfois à des guides d’utilisation (souvent appelées vignettes), à un fichier NEWS documentant les changements apportés au package lors de mises à jour, etc. Pour les packages sur le CRAN, toutes les fiches d’aide et le fichier descriptifs sont regroupés dans un fichier PDF. On retrouve ce PDF directement sur le CRAN (dans Reference manual), et non par le fenêtre d’aide de R (par exemple http://cran.r-project.org/web/packages/ggplot2/ggplot2.pdf). La documentation sert à expliquer comment utiliser les fonctions et à décrire ce que permettent de faire les fonctions. Il arrive (assez fréquemment malheureusement) que les fiches d’aide soient peu bavardes à propos des calculs effectués par une fonction. La fiche d’aide contient parfois des références qui peuvent nous éclairer. Si ce n’est pas le cas, on est parfois contraint d’aller voir directement dans le code source pour comprendre ce que fait une fonction. Code source Étant donné que R est un logiciel libre, on peut avoir accès au code source du R de base, ainsi qu’à celui de n’importe quel package R. Accéder au code source est parfois simple. Il suffit de soumettre le nom d’une fonction dans la console (sans parenthèses) pour que le code source de la fonction soit affiché. On peut aussi faire afficher ce code dans une fenêtre indépendante avec la fonction edit. Pour les fonctions cachées, il faut utiliser ::: ou getAnywhere comme mentionné ci-dessus. Pour certaines fonctions, le code source est par contre écrit dans un autre langage que R. Par exemple, le code R de la fonction var du package stats contient uniquement de la validation d’arguments. var ## function (x, y = NULL, na.rm = FALSE, use) ## { ## if (missing(use)) ## use <- if (na.rm) ## "na.or.complete" ## else "everything" ## na.method <- pmatch(use, c("all.obs", "complete.obs", "pairwise.complete.obs", ## "everything", "na.or.complete")) ## if (is.na(na.method)) ## stop("invalid 'use' argument") 7 ## if (is.data.frame(x)) ## x <- as.matrix(x) ## else stopifnot(is.atomic(x)) ## if (is.data.frame(y)) ## y <- as.matrix(y) ## else stopifnot(is.atomic(y)) ## .Call(C_cov, x, y, na.method, FALSE) ## } ## <bytecode: 0x00000000045828e0> ## <environment: namespace:stats> Le coeur du calcul est fait dans une fonction C, appelée à la dernière ligne du corps de la fonction à l’aide de la fonction .Call. Il est aussi possible de voir ce code C. On le trouvera dans les fichiers d’installation de R. L’article suivant explique comment faire. Ligges, U. (2006). R Help Desk: Accessing the Sources. R News, vol. 6, no. 4, p. 43-45. http://cran.r-project. org/doc/Rnews/Rnews_2006-4.pdf Création de packages R Pour créer un package R, il faut d’abord développer une structure de fichiers similaires à ce que l’on retrouve dans n’importe quel package source. Pour voir de quoi à l’air une telle structure de fichier, il suffit de : • télécharger un package source à partir du CRAN (par exemple ggplot2_1.0.1.tar.gz sur http://CRAN. R-project.org/package=ggplot2), • décompresser le fichier (il y a 2 étapes de décompression à effectuer). L’exemple utilisé ici, soit le package ggplot2, est un gros package. Seuls certains de ses fichiers et dossiers sont obligatoires dans tout package. Après avoir développé les fichiers sources, il faut compiler le package. Pour faire cette étape sur Windows, il faut d’abord s’assurer d’avoir les bonnes installations. Les Rtools doivent être installés sur notre ordinateur (voir le guide d’installation ou de mise à jour de R et RStudio). Étape 1. Écrire les fonctions Cette étape fait appel à ce que l’on a appris dans les cours Création de fonctions en R et Tests et exceptions en R. Lorsque l’on crée des fonctions dans le but de les inclure dans un package, il faut garder en tête le chemin de recherche complet qu’utilisera R lors de l’exécution de ces fonctions (voir ci-dessus). Dans ce chemin de recherche, on ne peut pas se fier au contenu de l’environnement de travail, car il varie constamment en cours de session. On ne peut pas non plus se fier aux packages chargés. En effet, la liste des packages chargés varie aussi en cours de session et d’un utilisateur à l’autre. Ainsi, dans le corps des fonctions d’un package, on peut faire appel à des variables locales, à d’autres objets dans le package (publiques ou privés) et à des objets du package R de base, qui est toujours inclus dans le chemin de recherche. Si on souhaite faire appel à des objets autres, par exemple des fonctions provenant d’autres packages, il faudra faire le nécessaire pour inclure ces fonctions dans l’environnement des objets importés par le package. Aussi, si notre but est éventuellement de rendre notre package public sur le CRAN, il faut respecter les politiques du CRAN : http://cran.r-project.org/web/packages/policies.html. La plus importante de ces politiques est que notre package doit passer le R CMD check --as-cran sans erreurs ni avertissements (on en reparle plus loin). Pour passer cette vérification sans problèmes, notre code ne doit pas, entre autres : 8 • contenir des symboles non-ASCII (donc pas d’accents, même dans nos commentaires), • utiliser d’association partielle d’argument (donc on doit s’assurer d’utiliser le nom complet des arguments dans les appels de fonction), • toujours utiliser comme valeurs logiques TRUE ou FALSE (donc pas de T ou F). Étape 2. Créer la bonne structure de fichiers Un package dans sa version source est simplement un répertoire de fichiers compressés. Cependant, ce répertoire doit comprendre des fichiers et des sous-répertoires portant des noms précis. On peut créer cette structure de fichiers à l’aide de la fonction package.skeleton. Cependant, on peut aussi créer manuellement les dossiers et fichiers. Il faut d’abord créer un dossier portant le nom du package. Voici ce que doit contenir obligatoirement ce dossier. Dossier nommé “R” Ce dossier doit comprendre des fichiers de scripts R (portant l’extension .R) contenant le code de création des fonctions ainsi que les commentaires roxygen2 si c’est l’outil que l’on utilise pour générer la documentation (on y revient plus loin). Le développeur peut choisir les noms qu’il veut pour ces fichiers et il peut y répartir le code source comme il le veut. Évidemment, une bonne pratique est de répartir le code source de façon à ce que ce soit facile de s’y retrouver. Dossier nommé “man” Ce dossier doit comprendre des fichiers sources de fiches d’aide R (portant l’extension .Rd). On va voir à la prochaine étape comment écrire ces fichiers. Fichier nommé “DESCRIPTION” Il s’agit d’un fichier très important pour la compilation du package. C’est un fichier court, comportant de l’information de base sur le package. Cependant, ce fichier doit respecter une syntaxe précise. Référence officielle concernant ce fichier : http://cran.r-project.org/doc/manuals/r-release/R-exts.html#The-DESCRIPTION-file Exemple : Package: monpkg Type: Package Title: Distance de Manhattan Version: 1.0 Date: 2015-03-26 Author: Sophie Baillargeon Maintainer: Sophie Baillargeon <[email protected]> Description: Calcul de la distance de Manhattan entre deux points. License: GPL-3 Fichier nommé “NAMESPACE” C’est un fichier qui permet de définir quels objets sont accessibles dans un package, c’est-à-dire exportés de l’espace de noms du package. Ce fichier permet aussi d’identifier quelles fonctions provenant d’autres packages sont utilisées dans le package, donc de définir le contenu de l’environnement des objets importés par le package. On va voir plus loin comment utiliser roxygen2 pour écrire correctement ce fichier. 9 Autres fichiers et dossiers Un package peut contenir plusieurs autres fichiers et dossiers. Cependant, ces derniers ne sont pas obligatoires. Autres dossiers parfois nécessaires : • Dossier nommé “data” : Si le package contient des jeux de données, ils doivent se trouver dans ce dossier. • Dossier nommé “src” : Si le package contient du code C, C++ ou Fortran, il doit se trouver dans ce dossier. • Dossier nommé “inst” : Si le package contient de la documentation autre que les fiches d’aide (par exemple un guide d’utilisateur appelé vignette), il doit se trouver dans ce dossier. • etc. : http://cran.r-project.org/doc/manuals/r-release/R-exts.html#Package-subdirectories Autres fichiers que l’on souhaite parfois ajouter : • Fichier nommé “NEWS” : Ce fichier décrit les modifications apportées à un package lors d’une mise à jour. Sa mise en forme n’est pas vraiment importante. • etc. : http://cran.r-project.org/doc/manuals/r-release/R-exts.html#Package-structure Étape 3. Écrire la Documentation des fonctions et du package Documenter ses fonctions est en fait une étape intégrée au développement des fonctions. Cependant, il faut maintenant écrire la documentation dans un format qui générera correctement les fiches d’aide qui doivent être incluses dans le package. Ces fiches d’aide proviennent en fait de fichiers portant l’extension .Rd. Cependant, on ne verra pas comment éditer directement ces fichiers. On va plutôt apprendre à faire ça en utilisant roxygen2. Le package roxygen2 est un outil qui permet de générer des fichiers .Rd ainsi que le fichier NAMESAPCE de façon automatique, à partir de commentaires intégrés au code. Rapellons que dans un package il faut documenter : - les fonctions publiques Il est essentiel de faire des fiches d’aide pour ces fonctions, afin que tout utilisateur comprenne comment appeler correctement la fonction. Si un utilisateur a mal compris la documentation et fourni par erreur une valeur d’argument invalide en entrée, il est souhaitable que la fonction retourne une erreur informative. Le code de ces fonctions publiques comporte donc typiquement de la validation des arguments fournis en entrée. À l’opposé, les fonctions privées ou internes ne sont pas conçues pour être appelées par n’importe quel utilisateur. On cache donc ces fonctions en ne les exportant pas d l’espace de noms et en ne les documentant pas officiellement. Il est tout de même bon de documenter minimalement ces fonctions pour nous-mêmes, mais on n’a pas à produire de fiches d’aide pour elles. Pour ne pas alourdir ces fonctions, on valide leurs arguments uniquement si on ne peut pas contrôler les valeurs fournies en entrée. - les méthodes pour des fonctions génériques On peut leur faire une fiche d’aide indépendante ou encore les documenter dans la même fiche d’aide que la fonction qui crée les objets de la classe en question. - les jeux de données Chaque jeu de données dans un package devrait être décrit dans une fiche d’aide pour expliquer son contenu. - le package lui-même On doit créer une fiche d’aide présentant le package. 10 Comment écrire de la documentation avec roxygen2? Exemples : D’abord, voici des exemples de scripts R contenant des commentaires roxygen2. Des explications se retrouvent après les exemples. Fichier ./R/Manhattan.R : #' Distance de Manhattan #' #' Calcule la distance de Manhattan entre deux points #' #' @param pt1 Un vecteur numerique des coordonnees du premier point. #' @param pt2 Un vecteur numerique des coordonnees du deuxieme point. #' #' @return une seule valeur : la distance de Manhattan entre #' \code{pt1} et \code{pt2} #' #' @author Sophie Baillargeon #' #' @export #' #' @examples #' Manhattan(pt1 = c(0,-5), pt2 = c(0,-15)) Manhattan <function(pt1, pt2) { # Validation des arguments if (length(pt1) != length(pt2)) stop("'pt1' and 'pt2' must have the same length") if (!is.null(dim(pt1)) || !is.null(dim(pt2))) warning("'pt1' and 'pt2' are treated as dimension 1 vectors") # Calculs sum(abs(pt1 - pt2)) } Fichier ./R/Manhattan2.R : #' #' #' #' #' #' #' #' #' #' #' #' #' #' #' #' #' Distance de Manhattan Calcule la distance de Manhattan entre deux points Utilise la fonction \code{\link{dist}} du package \pkg{stats}. @param pt1 Un vecteur numerique des coordonnees du premier point. @param pt2 Un vecteur numerique des coordonnees du deuxieme point. @return \item{dist}{ la distance de Manhattan entre \code{pt1} et \code{pt2} } @return \item{call}{ une copie de l'appel de la fonction } @author Sophie Baillargeon @export @importFrom stats dist 11 #' @examples #' Manhattan2(pt1 = c(0,-5), pt2 = c(0,-15)) Manhattan2 <- function(pt1, pt2) { call <- match.call() dist <- dist(rbind(pt1, pt2), method = "manhattan") list(dist = as.vector(dist), call = call) } Fichier ./R/print.Manhattan.R : #' @rdname Manhattan #' @method print Manhattan #' @param x Un objet produit par la fonction \code{Manhattan}, a afficher. #' @param \dots D'autres arguments passea a d'autres methodes. #' @export print.Manhattan <function(x, ...) { cat("Manhattan distance between 'pt1' and 'pt2' :", x$dist) invisible(x) } Fichier ./R/monpkg.R : #' Distance de Manhattan #' #' Distance de Manhattan entre deux points #' #' \tabular{ll}{ #' Package: \tab monpkg\cr #' Type: \tab Package\cr #' Version: \tab 1.0\cr #' Date: \tab 2015-03-26\cr #' License: \tab GPL-3\cr #' } #' #' @name monpkg-package #' @aliases monpkg-package monpkg #' @docType package #' @author Sophie Baillargeon #' #' Maintainer: Sophie Baillargeon <sophie.baillargeon@@mat.ulaval.ca> #' @keywords package NULL #' #' #' #' #' #' #' #' Points aleatoires Coordonnes en deux dimensions de 10 points aleatoires. @name points @docType data @format Une matrice contenant 10 points designes par les coordonnees suivantes. 12 #' \describe{ #' \item{X}{ coordonnee en X } #' \item{Y}{ coordonnee en Y } #' } #' @keywords datasets #' @examples #' data(points) #' Manhattan(pt1 = points[4, ], pt2 = points[8, ]) NULL Explications : Un commentaire roxygen2 doit débuter par le symbole #'. Pour les fonctions et les méthodes pour des fonctions génériques, il suffit de mettre en entête au code source les commentaires roxygen2 qui généreront la documentation. Pour le package et les jeux de données, on ajoute un fichier dans le dossier “R”. On met dans ce fichier .R les commentaires roxygen2 pour chaque fiche d’aide, tous suivis d’une ligne avec le code : NULL La première phrase de ces commentaires doit être le titre de la fiche d’aide. Cette phrase doit être suivie d’une ligne vide, puis du texte à mettre dans la section Description. Si on souhaite avoir une section Details, il faut mettre à la suite de ce texte une ligne vide. Tout le texte après cette ligne vide, mais avant les lignes débutant par un tag roxygen2 formera la section Details. On insère ensuite toutes les lignes débutant par des tags. Il faut obligatoirement décrire : • les paramètres en entrée avec le tag @param et • la sortie avec le tag @return. Il est aussi essentiel de mettre les tags pour l’écriture du NAMESPACE : • le tag @export exporte une fonction du NAMESPACE (donc la rend publique), • le tag @importFrom assure l’importation des fonctions provenant d’autres packages qui sont utilisées dans le code de notre package. On peut ajouter les informations suivantes : • • • • les noms des auteurs avec le tag @author, des références avec le tag @references, des liens vers les fiches d’aide de fonction en lien avec la fonction documentée avec le tag @seealso, etc. : voir les vignettes du package roxygen2 http://CRAN.R-project.org/package=roxygen2. Les méthodes doivent être déclarées avec le tag @method. Si on veut jumeler des fiches d’aide, on a besoin du tag @rdname. On peut contrôler le nom de la fiche d’aide avec le tag @name. Sans ce tag, la fiche d’aide porte le nom de la fonction qui suit le bloc de documentation roxygen2. Pour une documentation de package ou d’un jeu de données, c’est la ligne de code NULL qui suit le bloc de documentation. Il faut donc obligatoirement dans ce cas un tag @name. Dans ce cas, il faut aussi spécifier le type de documentation avec le tag @docType. 13 Il est recommandé de toujours mettre des exemples dans une fiche d’aide. Dans la documentation roxygen2, ceux-ci doivent être ajoutés à la fin du bloc de documentation, après le tag @examples. Dans les commentaires roxygen2, les tags de mises en forme recommandés dans les fichiers .Rd (par exemple \code{}, \pkg{}, \item{}, \link{}, \dots, etc. http://cran.r-project.org/doc/manuals/r-release/R-exts. html#Marking-text) devraient toujours être employés. Comment générer les fichiers .Rd et le fichier NAMESPACE ? Il suffit de lancer la commande roxygenize du package roxygen2. On peut le faire directement dans la console, ou encore par le menu de RStudio (voir prochaine section). Étape 4. Compiler et vérifier le package Cette étape se réalise avec les commandes : • R CMD check, • R CMD build, • R CMD INSTALL. Ces commandes ne sont pas lancées dans la console R. Elles sont lancées dans le terminal sous Linux ou OS X (Mac) et dans une fenêtre invite de commandes sous Windows. Il faut avoir les bons outils sur son ordinateur (voir le guide d’installation ou de mise à jour de R et RStudio) : • R, • Rtools, • compilateur LaTeX si on veut générer la documentation en PDF. RStudio peut lancer pour nous les commandes de compilation et de vérification. Le logiciel rend le processus vraiment plus simple que de lancer les commandes manuellement dans le terminal ou l’invite de commandes. On apprendra donc seulement comment compiler et vérifier un package avec RStudio Sous-étape a) Créer un projet RStudio avec notre package • • • • Par le menu File -> New Project. . . , sélectionner Existing Directory, sélectionner le dossier portant le nom du package et contennant les fichiers source, cliquer sur Create Project. Le projet sera créé et ouvert. Ça ajoute des fichiers dans le dossier de notre package. On ne se préoccupera pas de ces fichiers. Ils seront automatiquement ignorés lors de la compilation du package avec RStudio. Sous-étape b) Configurer les options de RStudio Options globales (à faire une seule fois) : • par le menu Tools -> Global Options. . . , • dans Packages, décocher Cleanup output after successful R CMD check. 14 Options du projet (à faire pour chaque nouveau projet) : • par le menu Tools -> Project Options. . . ; • sans Build Tools : – cocher Generate Documentation with Roxygen, – cliquez sur Configure, puis cocher : NAMESPACE file; • si vous n’avez pas de compilateur LaTeX sur votre ordinateur, ajoutez l’option suivante à R CMD check : –no-manual. Sous-étape c) Compiler à partir du menu Build de RStudio Il est préférable de toujours d’abord s’assurer que le package passe sans erreur ou avertissements problématiques la vérification faite par la commande R CMD check. Ensuite, on peut compiler le package, soit dans sa version source ou binaire . • Pour créer le package source (qui est aussi la version Linux/Unix) : menu Build -> Build Source Package. • Pour vérifier le package : menu Build -> Check Package. • Pour créer le package binaire (pour Windows) : menu Build -> Build Binary Package La compilation Build ans Reload est pratique en cours de travail. Elle permet de compiler le package dans le bon format pour notre système d’exploitation, l’installer (donc remplacer l’ancienne installation par la nouvelle) et charger de nouveau le package (avec la commande library). Étape 5. Au besoin, mettre à jour le package Lors d’une mise à jour de notre package, il faut : Sous-étape a) Incrémenter le numéro de version dans le fichier DESCRIPTION ainsi que dans la fiche d’aide du package. Sous-étape b) Faire les mises à jour dans le code Sous-étape c) Documenter les modifications dans les commentaires roxygen2 produisant les fiches d’aide ainsi que dans le fichier NEWS. Sous-étape d) Recompiler le package 15 Références • R Core Team (2015). Writing R Extensions. R Foundation for Statistical Computing. Chapitre 4. http://cran.r-project.org/doc/manuals/r-release/R-exts.pdf • Wickham, H. (2015). R packages. O’Reilly, à paraître. http://r-pkgs.had.co.nz/tests.html • Wickham, H., Danenberg, P., and Eugster, M. (2014). roxygen2: In-source documentation for R. R package version 4.1.0. http://CRAN.R-project.org/package=roxygen2 Accéder au code source : • Ligges, U. (2006). R Help Desk: Accessing the Sources. R News, vol. 6, no. 4, p. 43-45. http: //cran.r-project.org/doc/Rnews/Rnews_2006-4.pdf 16