Packrat ou comment gérer ses packages R par projet

  • Qui ne s'est jamais retrou­vé coin­cé entre deux pro­jets R uti­li­sant deux ver­sions dif­fé­rentes d'un même package ?
  • Qui n'a jamais eu cette idée folle, un jour d'inventer un cas d'école (via R) qu'il sou­hai­tait par­ta­ger ?
  • Qui n'a jamais eu à cher­cher quelle ver­sion de package est néces­saire avec un code récu­pé­ré d'un col­lègue pour qu'il fonc­tionne comme celui du dit col­lègue ?
  • Qui n'a jamais ins­tal­lé nombre de packages dans sa librai­rie pour divers pro­jets et n'a jamais osé les dés­ins­tal­ler par peur que des pro­jets ne fonc­tionnent plus ?
  • Qui n'a jamais mis à jour un package dans un pro­jet pour qu'il fonc­tionne, et ain­si ces­sé de faire fonc­tion­ner un autre pro­jet ?
  • Qui n'a jamais mis à jour par erreur un package et invo­lon­tai­re­ment TOUTES ses dépen­dances avec la même consé­quence que ci-des­sus ?

 

Je vais m'arrêter là, je pense que vous avez com­pris que la ges­tion de packages sous R est une source d'erreurs faciles. Mais pas d'inquiétude :

Packrat fait tout ça , Packrat est simple, Packrat vous veut du bien !

Packrat c'est aus­si un joli petit rat des bois
Cré­dit : Cali­for­nia Depart­ment of Fish and Wild­life — https://​flic​.kr/​p​/​A​U​B​cSL

 

Packrat ? Kézako ?

Packrat c'est un petit package R.

"Encore un ?!" vous allez me dire, oui mais il va vous sim­pli­fier la vie car il va rendre vos pro­jets R :

    • Indé­pen­dants : ins­tal­ler un nou­veau package ou le mettre à jour dans votre pro­jet ne va pas impac­ter tous vos autres pro­jets R (qu'ils aient été déve­lop­pés avec packrat ou non)
    • Por­tables : votre pro­jet sera déplaçable/​partageable d'un poste à un autre, et même d'un sys­tème d'exploitation à un autre (com­pi­la­tion dif­fé­rente vous me dites ? Kein pro­blem fräu­lein ! /​ T'inquiète pau­piette). Les ins­tal­la­tions des packages néces­saire à votre pro­jet seront faci­li­tées.
    • Repro­duc­tibles : packrat vous crée une sorte de sand­box ("un bac à sable", ou "un envi­ron­ne­ment iso­lé" pour les puristes) que vous pou­vez relan­cer n'importe où, n'importe quand pour retrou­ver votre pro­jet comme vous l'aviez lais­sé (et donc exac­te­ment les mêmes réul­tats) ! Il vous sau­ve­garde votre envi­ron­ne­ment et vous le remet à dis­po­si­tion dès que deman­dé.

 

Mais ! Mais ! Pour­quoi tu ne fais pas un envi­ron­ne­ment vir­tuel, une VM ?

Eh bien pour plu­sieurs rai­sons :

  • Pas besoin de devoir connaître d'autres lan­gages, outils logi­ciels. Connaître R suf­fit
  • Actuel­le­ment, et à ma connais­sance, il n'y a que Conda qui gère les envi­ron­ne­ments R
  • Ins­tal­ler une VM pour un petit pro­jet R c'est quand même sor­tir la mitrailleuse pour tuer un mous­tique

 

 

Comment ça marche ?

Si vous êtes comme la plu­part des gens orga­ni­sés (hep hep hep ! Reve­nez même si vous ne l'êtes pas), vous créez un réper­toire pour cha­cun de vos nou­veaux pro­jets R où vous ran­gez tout vos scripts et vos sources (et si vous ne le fai­siez pas, com­men­cez). Eh bien Packrat, à son lan­ce­ment, va se ser­vir de ce réper­toire pour en faire une sand­box avec votre librai­rie dédiée à l'intérieur et un ensemble de fichier et réper­toires néces­saire pour exploi­ter cor­rec­te­ment toutes les fonc­tion­na­li­tés :

  • packrat/packrat.lock : liste de tous vos packages dans le pro­jet avec leur ver­sion, les ver­sions des dépen­dances, les ver­sions des dépen­dances de dépen­dances, … Bref vous avez com­pris.
  • packrat/packrat.opts : spé­ci­fique à l'environnement d'exécution de votre pro­jet Packrat, il liste toutes les options que vous avez défi­nies (voir les options dis­po­nibles plus bas)
  • packrat/.Rprofile : indique à R d'utiliser la librai­rie interne au pro­jet lorsqu'on lance celui-ci depuis le réper­toire du pro­jet
  • packrat/​lib/​ : votre librai­rie interne (qui contient tout vos packages com­pi­lés à telle ou telle ver­sion et leurs dépen­dances com­pi­lées)
  • packrat/​src/​ : les sources de vos packages et de leurs dépen­dances

 

Mais ! Mais ! Pour­quoi tu t'embêtes à prendre tes sources si tu as déjà tes packages com­pi­lés ?

Et bien tout sim­ple­ment pour la por­ta­bi­li­té dont je vous par­lais plus haut, je m'explique : Packrat créé un snap­shot ("un ins­tan­ta­né" pour les puristes) de l'état de votre librai­rie. Il sau­ve­garde alors les sources des packages uti­li­sés et la ver­sions de ceux-ci. Par la suite lors du trans­fert de votre pro­jet Packrat de Win­dows à GNU/​Linux ou autre, vous aurez sim­ple­ment à lan­cer une com­mande qui res­tau­re­ra votre librai­rie (en recom­pi­lant les sources de vos packages de façon com­pa­tible à votre OS) dans son état ini­tial et vous voi­là prêt à pour­suivre votre tra­vail !

 

Et en pratique on fait comment ?

En théo­rie on va lire la documentation[1], mais comme je suis sym­pa je vous aide.

1ère étape : installer Packrat

Pour ça rien de plus clas­sique :

> install.packages("packrat")

Note : dans le cas où vous souhaiteriez être dans la dernière version sortie (beta et donc pas totalement stable), vous pouvez également installer la dernière version du dépôt github :

> install.packages("devtools")
> devtools::install_github("rstudio/packrat")

 

2ème étape : initialiser votre projet Packrat

Créez tout d'abord un répertoire selon le chemin[2] favori sur votre pc pour vos projets, puis dans R lancez :

> setwd("<leChemin>/PackratTest/")
> packrat::init(getwd())

Initializing packrat project in directory:
- "~/PackratTest"

Adding these packages to packrat:
_
packrat 0.4.6-1

Fetching sources for packrat (0.4.6-1) ... OK (CRAN current)
Snapshot written to "<leChemin>/PackratTest/packrat/packrat.lock"
Installing packrat (0.4.6-1) ...
OK (downloaded binary)
Initialization complete!

Restarting R session...

> packrat::on()
Packrat mode on. Using library in directory:
- "<leChemin>/PackratTest/packrat/lib"

Félicitation, vous voilà dans un projet Packrat !

Mais ! Mais ! C'est nul ! Ça n'a rien changé ton truc !

Effectivement, pour le moment il n'y a pas de changement notable dans votre projet à part les fichiers que j'ai cités avant. La force de ce package se révèle quand on commence à jouer avec les packages !

 

3ème étape : ajouter, supprimer, mettre à jour des packages

Par curiosité, regardez votre dossier

<leChemin>/packrat/lib/

 . Vous allez retrouver dedans votre sandbox compilée pour le système d'exploitation que vous utilisez, dans mon cas ce sera Windows comme vous pouvez le voir ci-dessous (rangez les couteaux à ce sujet, on trollera plus tard).

État de mon dossier de projet après une initialisation d'un projet packrat

 

Vous trouverez dedans l'ensemble des packages que vous allez ajouter par la suite dans votre projet. Pour le moment seul packrat est présent, les packages que vous ajouterez par la suite viendront se ranger ici.

Appliquons maintenant cela à un cas pratique.

  • Ajouter un package

Pour mon exemple je vais utiliser le package "e1071" (qui est utilisé pour la construction de modèles d'apprentissage supervisé de type Support Vecteur Machine ou SVM), mais n'importe lequel avec quelques dépendances ferait aussi bien l'affaire. Je débute donc classiquement par mon installation.

> install.packages("e1071", dependencies = TRUE)
also installing the dependencies ‘mlbench’, ‘randomForest’, ‘SparseM’, ‘xtable’

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.2/mlbench_2.1-1.zip'
Content type 'application/zip' length 1032847 bytes (1008 KB)
downloaded 1008 KB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.2/randomForest_4.6-12.zip'
Content type 'application/zip' length 177253 bytes (173 KB)
downloaded 173 KB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.2/SparseM_1.76.zip'
Content type 'application/zip' length 928883 bytes (907 KB)
downloaded 907 KB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.2/xtable_1.8-2.zip'
Content type 'application/zip' length 710243 bytes (693 KB)
downloaded 693 KB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.2/e1071_1.6-8.zip'
Content type 'application/zip' length 800579 bytes (781 KB)
downloaded 781 KB

package ‘mlbench’ successfully unpacked and MD5 sums checked
package ‘randomForest’ successfully unpacked and MD5 sums checked
package ‘SparseM’ successfully unpacked and MD5 sums checked
package ‘xtable’ successfully unpacked and MD5 sums checked
package ‘e1071’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
<Chemin>\AppData\Local\Temp\RtmpIL8kez\downloaded_packages

> packrat::snapshot()

Adding these packages to packrat:
_
SparseM 1.76
e1071 1.6-8
mlbench 2.1-1
randomForest 4.6-12
xtable 1.8-2

Fetching sources for SparseM (1.76) ... OK (CRAN current)
Fetching sources for e1071 (1.6-8) ... OK (CRAN current)
Fetching sources for mlbench (2.1-1) ... OK (CRAN current)
Fetching sources for randomForest (4.6-12) ... OK (CRAN current)
Fetching sources for xtable (1.8-2) ... OK (CRAN current)
Snapshot written to "<leChemin>/PackratTest/packrat/packrat.lock"

> packrat::status()
Up to date.
Comme vous pourrez le constater, e1071 n'est pas seul, il a ramené tous ses potes les dépendances avec lui comme on le lui a demandé ! Jetons maintenant un coup d’œil du côté de notre librairie packrat.

Répertoire src après l'installation d'un package

Tout les packages ont été installés et compilés pour notre OS courant. Et si on regarde du côté du dossier "src", on peut constater après la création du snapshot que les sources de chaque package ont été également téléchargées. On pourra donc aisément transporter notre projet et le recompiler pour un autre os au besoin.

Mais ! Mais ! Et si je veux ajouter des packages d'un dépôt externe à celui du CRAN ?

Pas de panique ! Vous ferez votre install.packages en précisant votre dépôt comme classiquement. Attention cependant à bien sélectionner la version source de votre packages, sans quoi vous vous retrouverez coincé pour l'exporter sur un OS différent.

Et si vous souhaitez directement ajouter un dépôt local, il existe une option qui le permet :

packrat::set_opts(local.repos = "path_to_repo")

 Prenez également garde dans ce cas à préciser un dépôt de packages source et non pas de packages compilés.

 

  • Supprimer un package

Il arrive que vous installiez un package par erreur (de "alr3" à "alr4" il n'y a qu'un pas, de 1), vient donc le besoin de retirer ce package de votre snapshot jusqu'ici tout propre. On voudra par exemple supprimer un package nommé "nnet" et supposément installé précédemment (package qui crée également des modèles d'apprentissage supervisé mais cette fois de réseaux de neurones) mais qui ne vous convient pas pour vos données.

> remove.packages("xtable")
Removing package from ‘D:/Documents/PackratTest/packrat/lib/x86_64-w64-mingw32/3.2.1’
(as ‘lib’ is unspecified)
Et là c'est le drame, un collègue qui vous parle en même temps (sagouin !), une rêverie sur votre futur prix Nobel, et vous supprimez le mauvais package (ici xtable) ! Regardons ce que nous raconte packrat pour nous consoler si on vérifie le statut de notre snapshot.
> packrat::status()

The following packages are tracked by packrat, but are no longer available in the local library nor present in your code:
_
xtable 1.8-2

You can call packrat::snapshot() to remove these packages from the lockfile, or if you intend to use these packages, use packrat::restore() to restore them to your private library.
Vous disposez donc d'une fonction de restauration de votre package perdu. Et si jamais vous souhaitiez réellement supprimer ce package, une mise à jour de votre snapshot permettra d'entériner cette décision (ce qui aura pour effet de supprimer la source dans le répertoire src).

 

Une astuce également intéressante pour la suppression de packages inutiles est de mettre simplement à jour de votre snapshot. Celui-ci en profite, si le cas se présente, pour vous signaler que certains des packages de votre librairie ne sont pas utilisés dans votre code. La commande clean vous permettra alors de supprimer ces packages devenus inutiles dans votre projet.

> packrat::status()
The following packages are installed but not needed:
_
nnet 7.3

Use packrat::clean() to remove them. Or, if they are actually needed by your
project, add library(packagename) calls to a .R file somewhere in your project.


 

  • Mettre à jour un package
De la même façon que vous installez un package, le besoin de mettre à jour un package se fera sûrement ressentir. Dans ce cas, effectuez votre mise à jour et pensez bien à faire un
packrat::snapshot  afin de bien informer packrat que ce package n'est pas un intrus !
Une bonne pratique à ce sujet est de toujours faire un
packrat::status  afin de vérifier l'impact de toute modification.

 

Mais ! Mais ! Ça devient franchement casse bonbon de faire ça à chaque fois !

C'est là qu'interviennent les options packrat (notre petit packrat/packrat.opts du début). Vous pouvez notamment programmer un auto snapshot d'un habile packrat::set_opts(auto.snapshot = TRUE).

Il existe plusieurs autres options mais je vous laisse le soin de RTFM [1] ;D

RTFM - xkcd - https://xkcd.com/293/

 

4ème étape : partager, exporter cet environnement et le restaurer

Vos voici donc, après peaufinage par vos petits soins, avec votre environnement R au complet pour exécuter les scripts que vous devez passer à votre collègue qui bosse sous un autre OS (Ubuntu par exemple, tssss quelle idée je vous jure :p). Cependant une étape reste à faire : le bundling, ou "empaquetage" en français.

Pour cela, pas la peine de se casser la tête, une fonction existe encore une fois pour cela (même si on ne va pas se le cacher, c'est un simple gzip dans les grandes lignes) :

> packrat::bundle()
The packrat project has been bundled at:
- "<leChemin>\PackratTest\packrat\bundles/PackratTest-2017-03-21.tar.gz"
# Oui le mélange "/" et "\" c'est Windows, c'est cadeau ...

Et ainsi votre collègue tout content n'aura plus qu'à récupérer la jolie archive, installer Packrat, et à utiliser la fonction complémentaire à cette première pour récupérer un environnement à l'identique, à l'exception que les packages R auront été compilés pour son OS.

Résultat du unbundle

 

Pour conclure

Packrat se révèle être très pratique et rapide pour vos projets se servant majoritairement des packages du CRAN ou d'un dépôt extérieur. Mais on pourra lui reprocher le cas où c'est un package personnel que vous souhaitez joindre, il faut alors définir un dépôt local. Une autre limitation dans cette lignée sera le cas où les sources des packages sont absentes (oui oui même sur le serveur du CRAN), ce qui empêchera de restaurer/recompiler les sources pour un OS sans avoir  passer par la case téléchargement.

Pour ceux qui aiment utiliser Rstudio, sachez qu'une version built-in existe pour vous donner un côté plus graphique à la gestion de votre environnement.

Enfin, si j'ai abordé ici la majorité des fonctionnalités de ce petit packages bien pratique, sachez qu'il reste quelques subtilités que je vous laisse découvrir par vous même en lisant la documentation qui est claire et concise (donc pas d'excuse, 4 pages ça se lit vite, zou zou !)

 

 Références

[1]  https://rstudio.github.io/packrat/

[2]  https://www.youtube.com/watch?v=CLuOd8xMRRo

 

Merci aux relecteurs Yoann M., Mathurin et Zazo0o pour leur temps et leur œil à l’affût !



Pour continuer la lecture :


Commentaires

3 réponses à “Packrat ou comment gérer ses packages R par projet”

  1. Super article, mer­ci ! 🙂

    J'ai une petite ques­tion concer­nant les mises à jour de packages.
    Disons que je mette à jour un package, je test le code, et là catas­trophe, plus rien ne fonc­tionne à cause d'une rup­ture de rétro­com­pa­ti­bi­li­té ! La bonne atti­tude est de résoudre le pro­blème, mais disons que je sou­haite plu­tôt res­tau­rer l'ancienne ver­sion du package pour cause de poil dans la main ou dead line ser­rée. Packrat per­met-il de faire cela plus faci­le­ment ? Ou non ?

    1. Mer­ci 😀

      Je n'ai pas tes­té cela, mais si j'en crois la docu­men­ta­tion et si tu n'as pas acti­vé l'option auto.snapshot, il est pos­sible de récu­pé­rer ton ancien envi­ron­ne­ment en fai­sant un packrat::restore(). Cela va en fait de remettre ton envi­ron­ne­ment dans l'état "sau­ve­gar­dé".
      Si jamais cela ne fonc­tionne pas, une bonne idée serait de faire un bundle pré­ven­tif avant toute mise à jour. Et si jamais la mise à jour ne convient pas, sup­pri­mer l'environnement et de-bund­ler l'archive 🙂

  2. […] Gar­der les anciennes ver­sions peut même être utile pour faire tour­ner un script qui néces­si­te­rait un package qui lui n’est dis­po­nible que pour une ancienne ver­sion de R ! A moins d’utiliser le package packrat. […]

Laisser un commentaire