Rのバージョン管理システム

R自体のバージョン管理を行うrigとパッケージの管理を行うrenvパッケージの使い方
R
rig
renv
virtual environment
Published

September 14, 2024

Modified

September 17, 2024

Rでデータ解析の再現性を保つためには、入力データと解析をしたコードをきちんと管理しておくのと同時に、 解析を行ったRの環境を再現可能にしておく必要がある。

この記事ではR自体のバージョン管理を行うrigと、 インストールしたRパッケージのバージョン管理を行うrenvパッケージの簡単な解説を行う。

GitHub - r-lib/rig: The R Installation Manager

The R Installation Manager. Contribute to r-lib/rig development by creating an account on GitHub.

https://github.com/r-lib/rig

Project Environments

A dependency management toolkit for R. Using renv, you can create and manage project-local R libraries, save the state of these libraries to a lockfile, and later restore your library as required. Together, these tools can help make your projects more isolated, portable, and reproducible.

https://rstudio.github.io/renv

Rのバージョン管理(rig

まずはRのバージョン管理をするモチベーションについて考えてみる。

Rはバージョンが変わるごとに、性能が上がったり、バグが修正されたり、機能が追加されたりする。 新たな機能の追加について考えてみると例えば、R 4.0からデフォルトのカラーパレットが変更されたり、 R 4.1から新たにパイプ演算子(|>)が追加されたりしている。 また、Biocoductorの各バージョンはR本体のバージョンと連動しており、 例えばBioconductor 3.19には正式にはR 4.4が必要となる。

このように新しいRの機能を試してみたり、あるいは新しく使用したいソフトウェアの要求から、 R本体のバージョンをアップデートしたいことがある。 一方で、R本体のバージョンを変更することで以前のバージョンでは動いていたプログラムが動作しなくなったり、 プロジェクトごとにRのバージョンを変更したいといった場合には、 R本体のバージョンを手軽に元に戻したり、切り替えたりする必要がある。 しかしながら、自分の手で複数のRのバージョンを切り替えるのはなかなか難しい。

R自体のバージョン管理を行う方法はいくつかあり、例えばdockerなどのコンテナ仮想化技術を使う方法などがある。 ここではより手軽にできる比較的新しい方法として、R専用のインストールマネージャーであるrigを紹介する。 rigを使うことで複数のバージョンのRをインストールし、必要に応じてRのバージョンを切り替えることが可能になる。

Caution

rigはまだ安定版ではない(記事の執筆時点でv0.7.0)ので、多少不具合が起きる可能性がある。

rig --version
RIG -- The R Installation Manager 0.7.0

rigはRustというプログラミング言語で書かれたコマンドラインツールで、 ターミナルなどのコマンドラインからrigコマンドを実行してR自体の管理を行う。 すでにRをインストールしている場合、そのRの管理をrigで行うことはできないので、あらかじめ入っているRをアンインストールしておく。

rigは多くのサブコマンドを提供している。rig --helpを実行することでサブコマンドの一覧や用例を見ることができる。

rig --help
Name:
  rig - manage R installations

Description:
  rig manages your R installations, on macOS, Windows, and Linux. It can
  install and set up multiple versions of R, and make sure that they work
  together.
  On macOS, R versions installed by rig do not interfere. You can run
  multiple versions at the same time. rig also makes sure that packages
  are installed into a user package library, so reinstalling R will not
  wipe out your installed packages.
  rig is currently experimental and is a work in progress. Feedback is much
  appreciated. See https://github.com/r-lib/rig for bug reports.

Usage: rig [OPTIONS] [COMMAND]

Commands:
  sysreqs    Manage R-related system libraries and tools (experimental)
  default    Print or set default R version [alias: switch]
  list       List installed R versions [alias: ls]
  add        Install a new R version [alias: install]
  rm         Remove R versions [aliases: del, remove, delete]
  system     Manage current installations
  resolve    Resolve a symbolic R version
  rstudio    Start RStudio with specified R version
  library    Manage package libraries [alias: lib] (experimental)
  available  List R versions available to install.
  run        Run R, an R script or an R project
  help       Print this message or the help of the given subcommand(s)

Options:
  -q, --quiet       Suppress output (overrides `--verbose`)
  -v, --verbose...  Verbose output
      --json        Output JSON
  -h, --help        Print help
  -V, --version     Print version

Examples:
  # Add the latest development snapshot
  rig add devel

  # Add the latest release
  rig add release

  # Install specific version
  rig add 4.1.2

  # Install latest version within a minor branch
  rig add 4.1

  # List installed versions
  rig list

  # Set default version
  rig default 4.0

Rのインストール(rig available, rig add

rig availableで利用可能なRのバージョン一覧を見ることができる。 rig available --helpでこのサブコマンドのヘルプメッセージを確認することができ、 例えば rig available --allですべての利用可能なRのバージョンを確認したりできる。

rig available --all
name   version  release date  type
------------------------------------------
4.1.0  4.1.0    2021-05-18    release
4.1.1  4.1.1    2021-08-10    release
4.1.2  4.1.2    2021-11-01    release
4.1.3  4.1.3    2022-03-10    release
4.2.0  4.2.0    2022-04-22    release
4.2.1  4.2.1    2022-06-23    release
4.2.2  4.2.2    2022-10-31    release
4.2.3  4.2.3    2023-03-15    release
4.3.0  4.3.0    2023-04-21    release
4.3.1  4.3.1    2023-06-16    release
4.3.2  4.3.2    2023-10-31    release
4.3.3  4.3.3    2024-02-29    release
4.4.0  4.4.0    2024-04-24    release
4.4.1  4.4.1    2024-06-14    release
next   4.4.1                  patched
devel  4.5.0                  devel

rig add {name}を実行すると{name}で指定したRをインストールすることができる。 rig add --helpでこのサブコマンドの詳細が確認できる。

rig add 4.4.1

インストールしたRの切り替え(rig list, rig default

rig listを実行するとインストールしたRの一覧を見ることができる。

rig list
* name       version    aliases
------------------------------------------
  4.1-arm64  (R 4.1.3)  
  4.2-arm64  (R 4.2.1)  
* 4.3-arm64  (R 4.3.2)  
  4.4-arm64  (R 4.4.1)  

左にアスタリスク(*)がついているRが現在有効化(コマンドラインでRと打って起動するもの)されているバージョンを示している。

R --version
R version 4.3.2 (2023-10-31) -- "Eye Holes"
Copyright (C) 2023 The R Foundation for Statistical Computing
Platform: aarch64-apple-darwin20 (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under the terms of the
GNU General Public License versions 2 or 3.
For more information about these matters see
https://www.gnu.org/licenses/.

複数のバージョンのRをインストールしている場合、rig default {name}を実行することで、 インストールしたRの中で有効化するRのバージョンを切り替えることができる。 rig defaultでバージョンを切り替えたあとで、rig listを実行すると有効化されているRが切り替わっていることがわかる。

rig default 4.4-arm64
rig list
* name       version    aliases
------------------------------------------
  4.1-arm64  (R 4.1.3)  
  4.2-arm64  (R 4.2.1)  
  4.3-arm64  (R 4.3.2)  
* 4.4-arm64  (R 4.4.1)  
R --version
WARNING: ignoring environment value of R_HOME
R version 4.4.1 (2024-06-14) -- "Race for Your Life"
Copyright (C) 2024 The R Foundation for Statistical Computing
Platform: aarch64-apple-darwin20

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under the terms of the
GNU General Public License versions 2 or 3.
For more information about these matters see
https://www.gnu.org/licenses/.

Rの解析環境の管理(renv

R本体のバージョン管理はrigを利用することでできる様になった。 では、Rのパッケージ管理は何を使ったら良いだろうか? renvは以下に挙げるような解析プロジェクトでよく必要となる条件に対して、 カッコで示すような便利な機能を提供し、条件を満たしてくれるRのパッケージである。

  • プロジェクトごとに異なるRのバージョン、異なるバージョンのパッケージを使いたい(仮想環境の提供
  • プロジェクトごとに使用しているR、パッケージのバージョンを記録しておきたい(バージョン管理
  • プロジェクトを共有した他の人や別のPCにおいても、プロジェクトのRの環境を再現したい(解析環境の再現

プロジェクトの仮想環境の初期化(renv::init()

プロジェクトごとに異なるバージョンのパッケージを使いたい場合、 そのプロジェクトだけで有効になる仮想的なRの環境を構築する必要がある。 renv::init()関数を使って、プロジェクトごとの仮想環境を初期構築をすることができる。

まずは、練習用のプロジェクトのディレクトリ(./test-renv/)を作って、magrittrパッケージを使うコードを書いたRのスクリプトファイル(./test-renv/scripts/use_magrittr.R)を追加する。

path_temp <- function(...) fs::path("test-renv", ...)
fs::dir_create(path_temp("scripts"))
writeLines(text = "library(magrittr)", con = path_temp("scripts", "use_magrittr.R"))
fs::dir_tree(path_temp(), recurse = 2, all = TRUE)
test-renv
└── scripts
    └── use_magrittr.R
test-renv/scripts/use_magrittr.R
library(magrittr)

次にrenv::init()関数を使ってプロジェクトの初期化を行う。 renv::init()関数を実行すると、プロジェクト内にあるスクリプトを解析して、 スクリプト内で使われているRのパッケージが記録される。 プロジェクト内にスクリプトがない場合は、起動時のR本体のバージョンと、 renvのバージョンだけが記録される。 また、bare = TRUEを設定すると初期化時のバージョンの記録はスキップされる。

renv::init(project = path_temp(), restart = TRUE)
- Linking packages into the project library ... Done!
The following package(s) will be updated in the lockfile:

# CRAN -----------------------------------------------------------------------
- magrittr   [* -> 2.0.3]
- renv       [* -> 1.0.3]

The version of R recorded in the lockfile will be updated:
- R          [* -> 4.3.2]

- Lockfile written to "~/blog/posts/2024/2024-09-14-rig-renv-intro/test-renv/renv.lock".
# 作成したプロジェクトの有効化
renv::load(project = path_temp())
# 現在のプロジェクトのディレクトリを確認
renv::project()
[1] "/Users/t_arae/blog/posts/2024/2024-09-14-rig-renv-intro/test-renv"
# 初期化によって、プロジェクトディレクトリ内にいくつかのものが作られている。
fs::dir_tree(path_temp(), recurse = 2, all = TRUE)
test-renv
├── .Rprofile
├── renv
│   ├── .gitignore
│   ├── activate.R
│   ├── library
│   │   └── R-4.3
│   └── settings.json
├── renv.lock
└── scripts
    └── use_magrittr.R

初期化すると、プロジェクトのディレクトリ内に新たにrenv/ディレクトリとrenv.lock, .Rprofileというファイルが作成される。それぞれの役割は以下の通り。

  • renv.lockファイルにはR本体のバージョンとプロジェクトで使用するパッケージの情報が記録される
  • renv/ディレクトリは仮想化に必要なコードとプロジェクトで使われるパッケージが含まれる
  • .RprofileはRが起動した際に自動で読み込まれる特別なRのスクリプトファイル

プロジェクトディレクトリでRを起動すると、まず .Rprofileが自動で読み込まれ、 その中でさらに仮想環境を有効化するためのコードが書かれたrenv/activate.Rを読み込むようになっている。

test-renv/.Rprofile
source("renv/activate.R")

renv/activate.R内のコードが実行されると、パッケージを読み込む場所がrenv/library/以下に設定され、 結果としてプロジェクトごとに異なるバージョンのパッケージを利用することが可能となる。

Note

プロジェクトの初期化には、renv::init()

パッケージ情報の更新(renv::status(), renv::snapshot()

プロジェクトで新しいパッケージを使用し始めたり、パッケージをアップデートすると、 記録しているバージョン情報も更新する必要がある。

renvでは、プロジェクト内で利用できる(インストールされている)パッケージの情報が、 renv.lockファイルに記録されている情報と一致しているかどうかなどの バージョン情報の確認を行ったり、renv.lockファイルの情報を更新する機能がある。

プロジェクト内の現在のバージョン情報の状況を確認するには、renv::status()を実行する。 問題がなければ以下のようなメッセージが出る。

renv::status()
No issues found -- the project is in a consistent state.

では、新しくmarkdownパッケージを使うRのスクリプトをプロジェクトに保存してみよう。

# 新たに`markdown`パッケージを使うコードが書かれたRのスクリプトファイルを追加
writeLines(text = "library(markdown)", con = path_temp("scripts", "use_markdown.R"))
test-renv/scripts/use_markdown.R
library(markdown)

この状態で、renv::status()を実行すると新たに追加されたスクリプトファイルが解析されて、 現在の状態の問題点が報告される。

# `markdown`パッケージが使われているがインストールも記録もされていない旨のメッセージが出る
renv::status()
The following package(s) are missing:

 package  installed recorded used
 markdown n         n        y   

See ?renv::status() for advice on resolving these issues.

メッセージが出たmarkdownパッケージをインストールして、再度renv::status()を実行してみる。

# `markdown`パッケージをインストールする
install.packages("markdown")
The following package(s) will be installed:
- commonmark [1.9.1]
- markdown   [1.13]
- xfun       [0.46]
These packages will be installed into "~/blog/posts/2024/2024-09-14-rig-renv-intro/test-renv/renv/library/R-4.3/aarch64-apple-darwin20".

# Installing packages --------------------------------------------------------
- Installing commonmark ...                     OK [linked from cache]
- Installing xfun ...                           OK [linked from cache]
- Installing markdown ...                       OK [linked from cache]
Successfully installed 3 packages in 6.1 milliseconds.
# もう一度、`renv::status()`を実行
# インストールはされているが`renv.lock`ファイルに記録されていない
renv::status()
The following package(s) are in an inconsistent state:

 package    installed recorded used
 commonmark y         n        y   
 markdown   y         n        y   
 xfun       y         n        y   

See ?renv::status() for advice on resolving these issues.

必要なパッケージがインストールできたところで、パッケージの情報をrenv.lockファイルに記録するには、 renv::snapshot()を実行する。

# `renv::snapshot()`を実行して、`renv.lock`にバージョンを記録する
renv::snapshot()
The following package(s) will be updated in the lockfile:

# CRAN -----------------------------------------------------------------------
- commonmark   [* -> 1.9.1]
- xfun         [* -> 0.46]

# RSPM -----------------------------------------------------------------------
- markdown     [* -> 1.13]

- Lockfile written to "~/blog/posts/2024/2024-09-14-rig-renv-intro/test-renv/renv.lock".
# もう一度、`renv::status()`を実行
# 今度は問題ない旨のメッセージが出る
renv::status()
No issues found -- the project is in a consistent state.

このようにして、renv::status()を実行してパッケージの齟齬がある場合には、 その不具合を解消した上で、renv::snapshot()を実行していくことで プロジェクトの環境のバージョン情報を更新していくことができる。

Note

バージョン情報の更新は、renv::status()で状態を確認しつつ、定期的にrenv::snapshot()

プロジェクト環境の再現(renv::restore()

ここまでの手順でプロジェクト固有の仮想環境を構築し、 環境内の状態(R本体とパッケージのバージョン)を記録することができる様になった。 では、この環境の状態を他の場所でも再現するにはどうしたら良いだろうか。

すべてのバージョンの情報はrenv.lockファイルに保存されているはずなので、 このrenv.lockファイルと解析に使っているRのスクリプトファイルがあれば再現できる様になっていると良い。 この作業は、renv::restore()関数で行うことができる。

それでは、先ほどまでの作業で構築したRの仮想環境を一度破棄して、 新しい作業用ディレクトリで同じ環境が構築できるか試してみよう。

まずは、renv.lockファイルとscripts/ディレクトリをひとつ上のディレクトリに退避(コピー)してから、 ディレクトリを消しておく。

Warning

通常はこのようにプロジェクトのディレクトリを削除することは当然しないので、 実際の自分のプロジェクトディレクトリでは真似しない様に

# 解析環境を再現するために、`renv.lock`ファイルをコピー
fs::file_copy(path_temp("renv.lock"), path_temp("../renv.lock"))
fs::dir_copy(path_temp("scripts/"), path_temp("../scripts/"))

# 元のディレクトリに戻って、テスト用のディレクトリを消す
renv::deactivate(clean = TRUE)
fs::dir_delete(path_temp())
Code
# 前の環境でロードされた`renv`をunloadしておかないと、`renv:::renv_imbue_self()`でエラーが出る。
unloadNamespace(asNamespace("renv"))

まずは前準備として、新しく環境再現用のプロジェクトディレクトリ(re-test-renv/)を作成し、 退避していたrenv.lockscripts/を新しいプロジェクトディレクトリに移動する

# 再現用の仮想環境を作るテスト用のディレクトリを作って、Working directoryを移動する
path_temp2 <- function(...) fs::path("re-test-renv", ...)
fs::dir_create(path_temp2())

# 退避していた`renv.lock`と`scripts/`を新しいプロジェクトディレクトリに移動する
fs::file_move(path_temp2("../renv.lock"), path_temp2("renv.lock"))
fs::file_move(path_temp2("../scripts"), path_temp2("scripts"))

fs::dir_tree(path_temp2(), recurse = 2, all = TRUE)
re-test-renv
├── renv.lock
└── scripts
    ├── use_magrittr.R
    └── use_markdown.R
# 仮想環境を初期化して、`renv.lock`ファイルから使用していた環境を復元する
renv::init(project = path_temp2(), bare = TRUE, restart = TRUE)
renv::load(project = path_temp2())
- None of the packages recorded in the lockfile are currently installed.
# 現在の仮想環境のディレクトリが移動していることを確認
renv::project()
[1] "/Users/t_arae/blog/posts/2024/2024-09-14-rig-renv-intro/re-test-renv"

現在の解析環境の状態をrenv::status()で確認してみよう。

renv::status()
The following package(s) are missing:

 package    installed recorded used
 commonmark n         y        ?   
 magrittr   n         y        y   
 markdown   n         y        y   
 xfun       n         y        ?   

See ?renv::status() for advice on resolving these issues.

renv.lockファイルに記録されているインストールされるべきパッケージは、 いまのところまだ一つもインストールされていないことがわかる。

これらのパッケージをインストールするにはrenv::restore()を使用する。

# `renv.lock`ファイルからプロジェクトに使っていたパッケージをインストール
renv::restore(lockfile = path_temp2("renv.lock"))
The following package(s) will be updated:

# CRAN -----------------------------------------------------------------------
- commonmark   [* -> 1.9.1]
- magrittr     [* -> 2.0.3]
- xfun         [* -> 0.46]

# RSPM -----------------------------------------------------------------------
- markdown     [* -> 1.13]

# Installing packages --------------------------------------------------------
- Installing commonmark ...                     OK [linked from cache]
- Installing magrittr ...                       OK [linked from cache]
- Installing xfun ...                           OK [linked from cache]
- Installing markdown ...                       OK [linked from cache]

メッセージから、test-renv/で使用していたパッケージと同じバージョンのパッケージがインストールされたことが確認できる。

では、再構築した仮想環境の状態を再確認してみよう。

renv::status()
No issues found -- the project is in a consistent state.

必要なパッケージが正しいバージョンで全てインストールされているため、 問題が見つからなかった旨のメッセージが出力された。

Code
# 終わったので消しておく
renv::deactivate(clean = TRUE)
fs::dir_delete(path_temp2())
Note

プロジェクト環境の再構築はrenv::restore()を使う。

まとめ

R自体の管理はrig、プロジェクトごとの環境の管理はrenvを使ってみよう。