Utilisation de packages R

Sophie Baillargeon, Université Laval

2021-03-28

Version PDF de cette page web : utilisation_packages_r_2021.pdf


Note préliminaire : Lors de leur dernière mise à jour, ces notes ont été révisées en utilisant R version 4.0.3. Le package ggplot2 version 3.3.3 et le package copula version 1.0-1 sont utilisés pour illustrer certains concepts. Pour d’autres versions, les informations peuvent différer.


Dans une session R, nous avons accès à un bon nombre d’objets R, principalement des fonctions et des jeux de données. Les objets accessibles sont ceux que nous créons ou ceux contenus dans les packages R chargés dans la session.

Un package R est simplement un regroupement de fonctions et de données documentées.

1 Installation et chargement d’un package R

Il est simple de charger en R des packages supplémentaires à ceux chargés par défaut lors de l’ouverture de session. Il suffit d’utiliser la fonction 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 deux étapes distinctes. L’installation n’a pas à être faite à chaque fois que le package est chargé.

Certains packages R sont installés automatiquement lors de l’installation de R. Ils ne sont pas pour autant tous chargés lors d’une ouverture de session.

La fonction installed.packages retourne des informations à propos des packages R installés sur l’ordinateur local. Voici un exemple obtenu sur mon ordinateur.

ip <- installed.packages()
head(ip, n = 3)
##           Package     LibPath                                       Version Priority
## abind     "abind"     "C:/Users/Sophie/Documents/R/win-library/4.0" "1.4-5" NA      
## acepack   "acepack"   "C:/Users/Sophie/Documents/R/win-library/4.0" "1.4.1" NA      
## ADGofTest "ADGofTest" "C:/Users/Sophie/Documents/R/win-library/4.0" "0.3"   NA      
##           Depends        Imports          LinkingTo Suggests   Enhances
## abind     "R (>= 1.5.0)" "methods, utils" NA        NA         NA      
## acepack   NA             NA               NA        "testthat" NA      
## ADGofTest NA             NA               NA        NA         NA      
##           License              License_is_FOSS License_restricts_use OS_type MD5sum
## abind     "LGPL (>= 2)"        NA              NA                    NA      NA    
## acepack   "MIT + file LICENSE" NA              NA                    NA      NA    
## ADGofTest "GPL"                NA              NA                    NA      NA    
##           NeedsCompilation Built  
## abind     "no"             "4.0.0"
## acepack   "yes"            "4.0.2"
## ADGofTest NA               "4.0.0"

La commande library() (donc la fonction library appelée sans lui fournir d’arguments), ouvre une fenêtre contenant aussi une liste des packages installés sur l’ordinateur local, mais moins détaillée. En RStudio, nous avons également accès à la liste des packages installés à partir de la sous-fenêtre nommée « Packages ».

Parmi ces packages, ceux qui étaient inclus dans les fichiers d’installation de R sont les suivants :

ip[
  ip[, "Priority"] %in% c("base","recommended"), 
  c("Package", "Priority")
]
##            Package      Priority     
## codetools  "codetools"  "recommended"
## foreign    "foreign"    "recommended"
## KernSmooth "KernSmooth" "recommended"
## Matrix     "Matrix"     "recommended"
## nlme       "nlme"       "recommended"
## base       "base"       "base"       
## boot       "boot"       "recommended"
## class      "class"      "recommended"
## cluster    "cluster"    "recommended"
## codetools  "codetools"  "recommended"
## compiler   "compiler"   "base"       
## datasets   "datasets"   "base"       
## foreign    "foreign"    "recommended"
## graphics   "graphics"   "base"       
## grDevices  "grDevices"  "base"       
## grid       "grid"       "base"       
## KernSmooth "KernSmooth" "recommended"
## lattice    "lattice"    "recommended"
## MASS       "MASS"       "recommended"
## Matrix     "Matrix"     "recommended"
## methods    "methods"    "base"       
## mgcv       "mgcv"       "recommended"
## nlme       "nlme"       "recommended"
## nnet       "nnet"       "recommended"
## parallel   "parallel"   "base"       
## rpart      "rpart"      "recommended"
## spatial    "spatial"    "recommended"
## splines    "splines"    "base"       
## stats      "stats"      "base"       
## stats4     "stats4"     "base"       
## survival   "survival"   "recommended"
## tcltk      "tcltk"      "base"       
## tools      "tools"      "base"       
## utils      "utils"      "base"

Lorsque nous souhaitons utiliser pour une première fois un package autre qu’un de la liste précédente, il faut d’abord l’installer.

De plus, tout comme le logiciel R lui-même, les packages sont périodiquement mis à jour par leurs auteurs. Il est bon de tenir à jour les packages que nous avons installés.

1.1 Différentes façons d’installer un package

L’installation de packages 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.

1.1.1 À partir du CRAN

Le CRAN est le dépôt informatique de packages R 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, il suffit d’utiliser 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,
  • .zip pour Windows,
  • .tgz pour macOS.

Aussi, install.packages peut télécharger et installer les packages dont dépend le package installé. C’est l’argument dependencies de la fonction install.packages qui détermine quelles « dépendances » sont installées. Par défaut, il s’agit des packages mentionnés dans les champs Imports, Depends et LinkingTo du fichier DESCRIPTION du package dont l’installation a été demandée. Ce type de fichier est présenté dans les notes sur la création de packages. Comme son nom l’indique, il sert à brièvement décrire le contenu d’un package, ainsi que ses configurations.

Le répertoire dans lequel les packages R sont installés par défaut est identifié dans le premier élément du vecteur retourné par la commande R suivante :

.libPaths()
## [1] "C:/Users/Sophie/Documents/R/win-library/4.0"
## [2] "C:/Program Files/R/R-4.0.3/library"

Sur mon ordinateur, les packages provenant de l’installation de R sont installés dans le répertoire "C:/Program Files/R/R-4.0.3/library" et les packages supplémentaires que j’ai installés sont dans le répertoire utilisateur "C:/Users/Sophie/Documents/R/win-library/4.0".

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.

1.1.2 À partir d’un dépôt informatique autre que le CRAN

En plus du CRAN, des packages R sont partagés à d’autres endroits sur le web, notamment sur :

  • le dépôt informatique de packages en bio-informatique Bioconductor,
  • un service web d’hébergement et de gestion de versions tel que GitHub, GitLab ou BitBucket.

Le package remotes offre des fonctions pour télécharger et installer directement à partir de ces sites (p. ex. fonctions install_bioc, install_github, install_gitlab et install_bitbucket). Notez que toutes ces fonctions sont aussi disponibles dans le package devtools, qui les importe du package remotes.

1.1.3 À partir d’un fichier compressé d’installation :

La fonction install.packages permet aussi d’installer des packages à partir de leur fichier compressé d’installation.

Si nous possédons le fichier compressé d’installation correspondant au système d’exploitation de notre ordinateur, le package peut être installé comme dans cet exemple :

install.packages("C:/coursR/ggplot2_3.3.3.zip", repos = NULL)

Si nous possédons uniquement le package source (.tar.gz), il est aussi possible d’installer le package à partir d’une plateforme Windows ou macOS, mais à la condition d’avoir le nécessaire au développement de packages (voir le Guide d’installation ou de mise à jour de R et RStudio). Dans l’appel à la fonction install.packages, l’argument type = "source" doit être ajouté comme suit.

install.packages("C:/coursR/ggplot2_3.3.3.tar.gz", type = "source", repos = NULL)

Toute installation à partir d’un fichier compressé peut aussi se réaliser par le menu « Install » de la sous-fenêtre « Packages » de RStudio, en sélectionnant : « Install from: > Package Archive File (…) ».

L’installation à partir d’un fichier compressé est utile, par exemple, lorsque nous avons besoin d’une ancienne version d’un package. Si nous laissons install.packages télécharger du CRAN un package, il téléchargera la dernière version. Il est possible que des mises à jour d’un package rendent certains de nos programmes non fonctionnels et qu’en conséquence nous souhaitions continuer d’utiliser une version antérieure du package. Pour obtenir une version d’un package qui n’est pas sa dernière version, nous pouvons aller sur sa page web du CRAN (par exemple http://CRAN.R-project.org/package=ggplot2), et télécharger manuellement la version dont nous avons besoin dans « Old Sources ». Le package remotes offre aussi la fonction install_version pour automatiser l’installation d’une version précise d’un package, qui n’est pas la version la plus récente.

2 Accéder au contenu d’un package R chargé

Une fois un package chargé en R avec la commande library, son contenu est accessible dans la session R. Nous avons vu dans des notes précédentes comment fonctionne l’évaluation d’expressions en R. Nous savons 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.

Le chargement de certains packages provoque aussi le chargement de packages dont ils dépendent. Ainsi, parfois plus d’un environnement est ajouté au chemin de recherche de R lors du chargement d’un package.

L’environnement d’un package contient typiquement les fonctions publiques et les données du package.

2.1 Fonctions publiques versus privées

Dans la phrase précédente, l’adjectif « publiques » n’est pas anodin. Les fonctions publiques d’un package sont celles destinées à être appelées par des utilisateurs. Elles ont été exportées de l’espace de nom du package (vu plus loin) de façon à être directement accessibles après chargement du package. 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 et é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 nous avons 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, nous avons créé une fonction pour faire le calcul, la modification doit être faite à un seul endroit. Nous gagnons du temps à long terme, le code est plus clair et les risques d’erreur sont minimisés. Il s’agit du principe Don’t Repeat Yourself, mentionné dans les notes sur les bonnes pratiques de programmation.

2.1.1 Environnement d’un package dans le chemin de recherche

La fonction ls permet de lister le contenu de l’environnement ajouté dans le chemin de recherche de R lors du chargement d’un package comme dans l’exemple suivant :

head(ls("package:stats"), n = 9)
## [1] "acf"                  "acf2AR"               "add.scope"           
## [4] "add1"                 "addmargins"           "aggregate"           
## [7] "aggregate.data.frame" "aggregate.ts"         "AIC"

Seuls les 9 premiers éléments de la liste sont affichés ici, car cette liste, qui énumère le contenu public du package stats (version 4.0.3), compte en réalité 449 éléments.

2.1.2 Espace de noms (namespace) d’un package

Il est aussi possible de lister tous les objets d’un package, publics ou privés, grâce à la fonction getNamespace, comme dans l’exemple suivant

head(ls(getNamespace("stats")), n = 10)
##  [1] "[.acf"         "[.formula"     "[.terms"       "[.ts"          "[.tskernel"   
##  [6] "[[.dendrogram" "[<-.ts"        "acf"           "acf2AR"        "add.scope"

Seuls les 10 premiers éléments de la liste sont affichés ici, car cette liste compte en réalité 1107 éléments.

Cet environnement, où tout le contenu d’un package est présent, à l’exception des jeux de données, 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 ::: (triple deux-points) 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): object 'Tr' not found

Nous arrivons cependant à y accéder par les commandes suivantes :

stats:::Tr
## function (matrix) 
## sum(diag(matrix))
## <bytecode: 0x0000000015e43368>
## <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: 0x0000000015e43368>
## <environment: namespace:stats>

Aussi, la méthode S3 de la fonction générique plot pour la classe lm fait partie du package stats, mais elle n’est pas publique.

plot.lm
## Error in eval(expr, envir, enclos): object 'plot.lm' not found

Nous pouvons tout de même y accéder avec la fonction getS3method

str(getS3method(f = "plot", class = "lm"))
## function (x, which = c(1, 2, 3, 5), 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) function(x, 
##     y, ...) panel.smooth(x, y, iter = iter.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"), iter.smooth = if (isGlm) 0 else 3, 
##     label.pos = c(4, 2), cex.caption = 1, cex.oma.main = 1.25)

Nous aurions aussi pu y accéder avec ::: ou getAnywhere.

2.1.3 Environnement englobant des fonctions d’un package

Dans les notes sur les fonctions en R, le sujet de l’évaluation d’un appel à une fonction est abordé. L’environnement englobant d’une fonction y est défini. Il 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, nul besoin d’utiliser ::: ou getAnywhere pour accéder aux fonctions internes.

2.2 Jeux de données

Souvent, 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.

head(ls("package:datasets"), n = 10)
##  [1] "ability.cov"   "airmiles"      "AirPassengers" "airquality"    "anscombe"     
##  [6] "attenu"        "attitude"      "austres"       "beaver1"       "beaver2"

Seulement les 10 premiers éléments de la liste sont affichés ici, car cette liste compte en réalité 104 éléments.

Cependant, les jeux de données sont parfois cachés. Ils sont alors 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 en fait 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. Nous y apprenons que le package copula contient un jeu de données nommé uranium. Cependant, ce jeu de données n’est pas accessible directement.

str(uranium)
## Error in str(uranium): object 'uranium' not found

La fonction data permet alors de charger le jeu de données dans l’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, mais il est bon de la connaître, car certains packages l’utilisent encore. Le désavantage de cette façon de faire est que le chargement d’un jeu de données avec la fonction data écrase tout objet portant le même nom que le jeu de données qui se trouverait dans notre environnement de travail.

2.3 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 ?, en fournissant comme argument le nom de la fonction. Les éléments suivants d’un package sont documentés dans une fiche d’aide :

  • les fonctions publiques,
  • les jeux de données,
  • les classes et méthodes S4 ou R6 publiques,
  • les méthodes S3 pour des fonctions génériques (optionnel),
  • le package lui-même (recommandé, mais pas obligatoire).

Une fiche d’aide peut servir à documenter plus d’un élément, par exemple un groupe de fonctions similaires ou une fonction retournant un objet d’une nouvelle classe et des méthodes pour des objets de cette classe.

La documentation complète d’un package s’ouvre en passant par :

help.start() > Packages > nom du package.

Nous avons ainsi accès à l’index du package, contenant des liens vers les fiches d’aide, mais aussi vers un le fichier DESCRIPTION du package, parfois vers des guides d’utilisation (souvent appelées vignettes), parfois vers un fichier NEWS documentant les changements apportés au package lors de mises à jour, etc. Notons que toute fiche d’aide comporte en pied de page un lien vers l’index de son package.

Pour les packages sur le CRAN, toutes les fiches d’aide ainsi que le fichier DESCRIPTION sont regroupés dans un fichier PDF. Ce PDF se retrouve directement sur le CRAN (dans le champ nommé Reference manual), mais pas dans la fenêtre d’aide de R (par exemple http://cran.r-project.org/web/packages/ggplot2/ggplot2.pdf).

La documentation sert à décrire ce que permettent de faire les fonctions et expliquer comment les utiliser. En plus d’exemples dans les fiches d’aide, certains packages possèdent des démonstrations, qui se démarrent avec la fonction demo, comme dans cet exemple :

demo(lm.glm, package = "stats", ask = TRUE)

La commande demo() ouvre une fenêtre contenant la liste de toutes les démonstrations disponibles pour les packages chargés dans notre session R.

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, nous sommes parfois contraints à aller voir directement dans le code source pour comprendre en détail ce que fait une fonction.

2.4 Code source

Étant donné que R est un logiciel libre, le code source de tout package R est accessible. 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é. Le code peut aussi être affiché dans une fenêtre indépendante avec les fonctions View ou 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, mis à part la dernière instruction qui appelle une fonction écrite en langage C. Cette fonction C nommée C_cov, qui réalise le coeur du calcul, est appelée en R à l’aide de la fonction d’interface .Call.

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")
##     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: 0x000000001258daa8>
## <environment: namespace:stats>

Il est possible de voir le code C de la fonction C_cov. Il se trouve dans les fichiers source de R, qui sont téléchargeables sur le site web suivant :
https://cran.r-project.org/sources.html


3 Résumé

Un package R est un regroupement de fonctions et de données documentées.

Installation et chargement d’un package R

Où se trouvent les fichiers du package ? .libPaths()

Accéder au contenu d’un package R chargé

  • Fonctions publiques :
    • directement accessibles par leur nom,
    • :: peut être utile en cas de conflit de nom;
  • Fonctions privées :
  • Jeux de données :
    • directement accessibles
    • ou accessibles grâce à la fonction data;
  • Documentation : ?, help, help.start, demo.
  • Code source :
    • code R : afficher la fonction (sans l’appeler), dans la console ou les fonctions View ou edit,
    • code dans un autre langage : fichiers sources.

Environnements reliés à un package R

  • Environnement d’un package dans le chemin de recherche :
    • fonctions publiques seulement;
    • souvent jeux de données, mais pas toujours;
    • commande pour énumérer son contenu : ls("package:<nomPackage>")
  • Espace de noms (namespace) d’un package :
    • tout le contenu, public et privé, du package (à l’exception des jeux de données);
    • commande pour énumérer son contenu : ls(getNamespace("<nomPackage>"))

Références