renv とは?
RStudioが開発を進めているRのPackage管理のためのパッケージである
パッケージ管理といえば、Pythonでは新しいパッケージが次々出ており、流れをキャッチアップするだけで一苦労だが、RではこれまでRStudio社のPackrat
くらい?しかなかったように思える(私が知らないだけかもしれないが)
パッケージ管理が必要な理由としては、Rの場合は主に分析の再現性を担保するためだと思う。とくに、複数人でRプロジェクトをおこなうときに威力を発揮する。また自分の場合、CIでテストを行うときやShiny Appを開発するときにも威力を発揮している
なぜrenv
が開発されているかの背景を理解するためにrenv
のProject pageに書いてあるGoalを見てみる
The goal is for renv to be a robust, stable replacement for the Packrat package, with fewer surprises and better default behaviors.
この一文から、Packrat
を代替しながら、より安定して使いやすいものを目指していることがわかる。Packrat
を使ってるRユーザはどれくらいいるのだろうか。少なくとも自分の周りでPackrat
使ってますという話はほとんど聞かない(自分はそこそこ使ってたほうだと思う)
(Packratの使い道を考えてみたがとても詳しいので、Packratの解説は省略します)
Packrat
との違い
renv
のPackrat
との違いはProject Pageに書かれている。大きいところとしては、renv.lock
というjson形式でRプロジェクトで使用しているパッケージのメタ情報を保存してくれることや、global cacheという仕組みでRプロジェクト間でパッケージを共有できる仕組みがある。そのため、Rプロジェクトを変更するごとに、毎回CRANにパッケージをダウンロードする待ち時間が発生するのはほとんどなくなった点が大きい
global cacheは簡単に言うと、ローカルのhomeディレクトリのような決められた配下にパッケージを保存して、Rプロジェクトで利用するときに、キャッシュがあるなら、そこへのリンク(正式にはシンボリックリンク)を貼ってくれる仕組みである
個人的な感想
Packrat
をそこそこ使ってた私の感想としては、global cacheにより待ち時間が減り、デフォルトの挙動が覚えやすいので、今のところ使いやすい印象です。そのため、Rでパッケージ管理したことがない方へも導入のしきいは低くなっていると感じます
参考情報
- Github : https://github.com/rstudio/renv
- Project page : https://rstudio.github.io/renv/
- "Using renv with Docker" のArticles読めばDocker Image作るときに楽になると思います
- Snapshot and Restore : https://environments.rstudio.com/snapshot
- この記事が流れをみるのにわかりやすい
インストール
2019-08-16時点では、CRANにはまだアップロードされていないので、Githubからインストールする
> remotes::install_github("rstudio/renv")
<snip>
> packageVersion("renv")
[1] ‘0.6.0.108’
基本的な使い方
同じホストでの作業
-
renv::init()
をする - Rコードを書く
-
renv::snapshot()
をたまにする - 作業を終えたら、
renv::snapshot()
をして、編集したファイルとともにrenv/
とrenv.lock
ファイルらをgit commitする
違うホストから使うとき
- git clone したのちに、
renv::restore()
- あとは同じ
それぞれ主に使うコマンドを簡単に解説する
renv::init()
renv
によるパッケージ管理を始めるために使用する
実行すると、renv/
というprivate R libraryの置き場と、.Rprofile
が作成される
.Rprofile
には、source("renv/activate.R")
が記載されており、Rプロジェクト開始とともにrenv
によるプロジェクト管理をスタートする処理が書かれている
> renv::init()
* Discovering package dependencies ... Done!
* Copying packages into the cache ... [300/300] Done!
* Resolving missing dependencies ...
* Querying repositories for available source packages ... Done!
Retrieving 'https://cloud.r-project.org/src/contrib/fclust_2.1.tar.gz' ...
OK [downloaded 86.2 Kb in 0.8 secs]
<snip>
完了後、.libPaths()
を実行してみると、private R libraryが使われている事がわかる(2つめはよくわかっていない)
> .libPaths()
[1] "/home/ooki/renv-sandbox/renv/library/R-3.6/x86_64-pc-linux-gnu"
[2] "/tmp/RtmpUk1Icd/renv-system-library"
このときprivate R library配下にパッケージのソースが置かれるのではなく、global cache配下(Linuxだと~/.local/share/renv
)に置かれ、private R libraryにはそこへのリンクが置かれる
$ ls -la ~/renv-sandbox/renv/library/R-3.6/x86_64-pc-linux-gnu/
<snip>
lrwxrwxrwx 1 ooki ooki 124 Aug 16 19:24 assertthat -> /home/ooki/.local/share/renv/cache/v4/R-3.6/x86_64-pc-linux-gnu/assertthat/0.2.1/87318c127c936afe4da4d066d1fd01c3/assertthat/
lrwxrwxrwx 1 ooki ooki 122 Aug 16 19:24 backports -> /home/ooki/.local/share/renv/cache/v4/R-3.6/x86_64-pc-linux-gnu/backports/1.1.4/8ed7589b3c92d5dc620c45b5f0909d9f/backports/
lrwxrwxrwx 1 ooki ooki 111 Aug 16 19:23 BH -> /home/ooki/.local/share/renv/cache/v4/R-3.6/x86_64-pc-linux-gnu/BH/1.69.0-1/a3839f6fcfa121ea0b5c4b3a0b42456e/BH/
<snip>
renv::snapshot()
このコマンドにより、Rプロジェクト配下のファイルに新たなライブラリが使われていたら、renv.lock
に書き込んでくれる。変更がない場合は、以下のようなメッセージがでる
> renv::snapshot()
* The lockfile is already up to date.
たとえば、新たにtidyr
パッケージを使うために、install.packages("tidyr")
と実行する。global cacheにすでに存在する場合は、そこへのリンクを貼ってくれるだけなのですぐに完了する
> install.packages("tidyr")
Installing tidyr [0.8.3] ...
OK (linked cache)
* Lockfile written to '~/renv-sandbox/renv.lock'.
library(tidyr)
と新たに.Rファイルに追加してから実行すると、再度snapshotを実行すると、tidyr
が使われていることをrenv
が発見してくれて、renv.lock
に書き込んでくれる。
> renv::snapshot()
The following package(s) will be added to the lockfile:
_
tidyr [0.8.3]
Do you want to proceed? [y/N]:
この辺の発見ロジックは、https://github.com/rstudio/renv/blob/master/R/dependencies.R#L488-L494 あたりのrenv::dependecies()
あたりにより実現されていると思われる。
(つい先日 pacman::p_load()
が renv::dependecies()
に対応していないIssueをあげたのですが、翌日には対応してくれるほどのスピード感だったので驚いた : https://github.com/rstudio/renv/issues/143 )
renv::restore()
別のマシンやCIからRプロジェクトと同じパッケージをインストールするときに使う。基本的にrenv.lock
ファイルさえあれば動くので、Gitでrenv.lock
を管理しておけばどこからでも同じ環境が再現しやすい。
今のところ自分はDocker ImageやCIのまっさらな環境に、renv::restore()
させてから、Testさせるときに使っている
> renv::restore()
The following package(s) will be installed:
_
BH [1.69.0-1]
R6 [2.4.0]
RColorBrewer [1.1-2]
<snip>
Do you want to proceed? [y/N]: y
<snip>
その他コマンド
renv::status()
renvによるパッケージの管理状態を知るコマンド(といってもあまり使わない)
> renv::status()
* The project is already synchronized with the lockfile.
renv::dependencies()
プロジェクトにあるソースとパッケージの関係を出力。おそらく、renv::snapshot()
等で使われる
> renv::dependencies()
Finding R package dependencies ... Done!
Source Package Require Version
1 /home/ooki/renv-sandbox/analysis.R dplyr
2 /home/ooki/renv-sandbox/analysis.R ggplot2
3 /home/ooki/renv-sandbox/analysis.R tidyr
4 /home/ooki/renv-sandbox/script.R remotes
5 /home/ooki/renv-sandbox/script.R renv
renv::hydrate()
ProjectのなかでSystem libraryから使われているPackageをprivate R libraryにインストールしてくれる。renv::init()
の中でこれが実行されている模様
> renv::hydrate()
renv::clean()
使ってないライブラリをPrivate R libraryからRemoveしてくれる。たまにお掃除したくなったときに使う
> renv::clean()
renv::settings$ignored.packages()
renv管理から無視するパッケージ(testやdevtoolsなどが該当するかと思う)を設定する
参考 : https://rstudio.github.io/renv/reference/settings.html
> renv::settings$ignored.packages()
character(0)
> renv::settings$ignored.packages("devtools", persist = FALSE)
> renv::settings$ignored.packages()
[1] "devtools"
renv::settings$use.cache(FALSE)
renvのglobal cacheを使わなくする
renv::settings$snapshot.type("simple")
renvのsnapshotの方法を変更する。デフォルトはpackrat
。simple
にしたら、もとのRのユーザライブラリのすべてをrenv.lock
に書き込もうとするようになる
今後
今のところ、version 0.7でCRANに登録予定。また、1.0に向けて実装は日々進んでいるので、今後も楽しみである。`Packratはあまり周りで使ってる人はいなかったが、
renv`は使い勝手といい、分析の再現可能性担保のためにも流行ってほしいなと個人的には思っているので、ぜひみんな使っていってほしい