はじめに

Rを用いた解析環境を構築についてまとめることにした。医学生物系の大学院生や研究者の多くはRによる解析を行うことが多い。これはおそらく歴史的なものだと思うが、解析用のパッケージがRに多いことに起因している。他にSPSSなどのGUIに特化した解析ソフトを使う人もいるが、生成AIが普及している現代において、無料で柔軟に使用できるRの解析環境は非常に有利である。

Rはオープンソースであり、コミュニティによって多くのパッケージが開発されている。これにより、特定の解析ニーズに応じたカスタマイズも可能だ。

しかしながら、パッケージ管理や環境をしっかり管理している人は多いとは言えない。解析環境を保存しなければ、せっかく行った解析も数年後には動かなくなっている事もあるだろう。再現性の担保は重要だと考える。

パッケージのバージョン管理

再現性の担保のために重要な点の1つは、パッケージのバージョン管理だ。同じパッケージでも最新のものかどうかで動作が異なる可能性がある。これを管理するパッケージでRでおそらくメジャーなのがrenvである。おそらくと書いたのは、Web上の情報量による判断だ。renvに関して簡単に解説する。

renvを使用することで、プロジェクトごとに異なるパッケージバージョンを管理でき、他のプロジェクトに影響を与えることなく環境を再現できる。

renvの仕組み

renvの仕組みはシンプルだ。たとえばプロジェクト内にRマークダウンファイルを作成し、コードを書くとする。コード内には様々なパッケージがインストールされて使用されている。ここでrenvはrenv.lockというファイルを作成し、プロジェクト内で使用されているパッケージのバージョンを全てメモする。ただそれだけとなっている。

パッケージはシステムファイル内に保存される

パッケージ本体は丁寧に使用しているOS環境毎にファイリングされ、renvファイル内に保存されるが、このrenvファイルはシステム内のキャッシュのシンボリックリンクとなっている。つまりパッケージの実体はプロジェクトのフォルダにはなく、システムファイル内に保存されている。この保存先はrenvが入っているプロジェクト内のRコンソールで下記のようなコマンドを実行すると知ることができる。

 renv::paths$cache()

まとめると、renvはパッケージのバージョンをrenv.lockにメモしており、それを基にシステムファイル内に保存されたパッケージを呼び出して使用している。

renv頻用のコマンド

renvの頻用コマンドは以下の通りである

プロジェクトにrenvをインストールする

install.packages("renv")

プロジェクトにrenvを導入する(renv.lockを作る)

renv::init()

パッケージを記録する

renv::snapshot()

解析の節目毎にこのコマンドでrenv.lockに記録する必要がある

現状確認

renv::status()

プロジェクト内にはあるのにrenv.lockに記録されていないパッケージなどを一覧で見ることができる。

renv.lockを読み込む

renv::restore()

renv.lockの情報からパッケージをインストールし、復旧ができる。つまり、PCが変わってもパッケージのバージョンをメモしたrenv.lockさえあれば環境を復旧できる。

プロジェクト内のパッケージを最新に更新する

renv::update()

Dockerでシステム環境を保存する

renvでパッケージの環境は保存できるが、システム環境やOSの情報は保存されない。Rのパッケージの中にはシステムの影響を受けるものが少なからず存在する。この問題を解決するのがDockerになる。Dockerを用いるとOSごと環境を構築できる。

調べるとDockerを用いてRstudioの解析環境を構築するような取り組みが成されており、Rockerと命名されている。

導入手順を記していく。

Dockerのインストール

これは公式ページに則ってPCにインストールすれば良い。デスクトップ版でもCLIでも特に問題ない。

Docker Imageのダウンロード

Docker Hub Container Image Libraryというページで使用できるImageを検索できる。ここでrockerと検索してみる。(Rockerの公式ページから探しても良い)

Imageというのが構築された解析環境と考えてよいだろう。Docker ImageはDockerfileという設計図のようなテキストファイルから生成されるが、一から作るのは素人には不可能なので、素直にRockerのImageを使用する。

使用できるOSに制限があり、だいたいlinux/amd64かlinux/arm64となっている。つまりWindowsでは使用できない。

rocker/rstudioを入手する

一番上のDocker Imageを使用してみる。ターミナルなどのシェルコマンドで

docker pull rocker/rstudio

とコマンドを入力する。Docker Imageがダウンロードされる。

Containerの起動

シェルコマンドで下記のように実行する。

docker run --rm -ti -e PASSWORD=yourpassword -p 8787:8787 rocker/rstudio

これでContainerを起動できる。

ローカルホストにアクセスすることでDockerから構築した環境を使用することができる。IDはrstudio、パスワードは設定した通りである。

バニラで使用するRockerの問題点

そのままRockerを使用すると使いにくすぎることに気づく。

  1. 完全に独立した環境なのでPCとファイルのやり取りができない
  2. 起動のたびに全て白紙に戻る→パッケージの再ダウンロードが必要

この問題をrenvとの連携で解決する。

docker-compose.ymlを作る

独自用語が多くてわかりにくいので一旦図解する。

docker-compose.ymlというファイルを作り、それを基にDocker Imageを起動する(=Container化する)ということができる。

先程のコマンドは単純にContainerを起動しただけだが、ここにコンテナバインドという手法を加える。

docker-compose.ymlというテキストファイルに例えば下記のように記載する

version: '3.8'
services:
  rstudio:
    image: rocker/rstudio:4.3.2
    volumes:
      - PCのRstudio用フォルダ:/home/rstudio
      - PCのrenvのキャッシュのフォルダ:/home/rstudio/.cache/R/renv
    environment:
      - PASSWORD=password
    ports:
      - "8787:8787"

どのバージョンのどのイメージを使うか、パスワードをどうするか、ポートをどうするかなどの設定を書き込めるが、重要なのはvolumesという部分だ。

:で囲んだ左をPC内のフォルダ、右をrocker内のフォルダで記載すると、Containerの内外をつなげることができる。

要はコンテナ内にプロジェクト内のファイルとキャッシュされたパッケージさえあれば良いのだから、必要な部分だけをPCから使えるようにする。厳密にはDockerの独立した環境というコンセプトから外れるが、このやり方が一番楽だと考えている(他の方法もあるにはある)。

docker-compose.ymlからContainerを起動する

docker-compose.ymlのあるディレクトリから下記のコマンドを実行するだけ

docker compose up

終了時は

docker compose down

完成

これでシステム環境とパッケージを完全に保存することが可能となった。プロジェクト内のファイルとdocker-compose.ymlだけ保存するだけで良いし、保存された情報は全てテキストなので軽量である。

さらに向こうへ

毎回絶対導入するシステム要件がある場合などは、Docker Imageを作り変える。Dockerfileと既存のDocker Imageを基に、新たなDocker Imageを作るということができる。つまり、あらかじめ欲しい環境を追加したImageを作ることができる。ただしこれは高度なうえ、生成AIに聞いたほうが早いので今回は解説しない。

また、さらに厳密さを求めるのであればプロジェクト毎にGitで管理するというのもありだろう。時間経過や編集の軌跡や記録も完全に記録することができる。ただこれも煩雑さを嫌って導入していない。

おわりに

ここまで厳密にする必要はないかもしれないが、このシステムは非常によくできていると個人的には考えている。導入難易度はやや高めだが、運用コストは低いので是非使ってみてほしい。

初めてDockerやrenvを使用する場合、学習曲線があるかもしれないが、長期的にはプロジェクトの再現性と安定性を大幅に向上させることができる。