Rのバッチモード
大規模なシミュレーションをRで行う場合のバッチモードについてです。シミュレーションなどを行う場合、最初はプログラムをキーボードから入力できるGUIの付いたRを起動して一つずつデータ発生が正しく動くこと、解析が動くことなどを順次確かめると思います。ただ、ある程度動くことが確認された後は、GUIから動かすのではなく、勝手に起動して全ての設定を終わられて欲しいと思います。そのような場合、Rのバッチモードを利用すると便利です。
例題の再掲(t検定のシミュレーション)
シミュレーションで、いくら同じようなプログラムを何度も実行するからといって、全く同じデータに全く同じ解析を行っても、全く同じ結果が求まるだけであり、時間とCPU資源、電気代の無駄です。同じ解析を行うにしても、発生するデータを変更するなど、多少なりとも異なった設定にて実行をすることと思います。そこで何通りか、ほとんど同じプログラムだけど設定を一部変更する方法について紹介したいと思います。ここでは例題として、以前に紹介したt検定のシュミレーションを例題として扱いたいと思います。プログラムをシミュレーションを前提として一部の設定を冒頭に持ってきて再掲いたしますと、
niter <- 1000 nsub <- 10 mean_a <- 120 mean_b <- 140 sd <- 20 filename <- "result.rds" result <- numeric(niter) for(i in 1:niter){ dat_a <- rnorm(nsub, mean_a, sd) dat_b <- rnorm(nsub, mean_b, sd) result[i] <- t.test(dat_a, dat_b, var.equal=TRUE)$p.value } probsig <- sum(result < 0.05)/1000 saveRDS(probsig, filename)
このプログラムで、例えばA群の真の平均値は120に固定したとして、B群の平均値を120、140、160、180としたときの有意となる確率の変化を知りたいとします。その場合、mean_bを120、140、160、180と変化させ、残りをそのままにして4回上のプログラムを実行すればいいわけです。このプログラムは、最後のsaveRDSで自動的に結果をファイルとして保存してくれます(読むにはreadRDS(filename))。さて、この4つのプログラムを実行する方法として、何通りかあり、それぞれについて以下で解説します。最初に、色々試した結果、私が最終的に使っているのは一番最後の環境変数による受け渡しをする方法です。なので、あまりR自体に関心がなく、どうするかだけを知りたい方は最後のところだけ目を通すのがいいと思います。
Rでプログラムを実行する方法
Rのパッケージにlittlerパッケージというものがあり、これも利用できるようですが、パッケージを使わない方法をここでは紹介いたします。
RGuiからの実行
Rでプログラムを実行するには、いくつかの方法があります。通常WindowsでRを起動して対話的にキーボードなどからプログラムから入力する際に使われるのは「RGui.exe」で、Windowsのプログラムメニューに登録されるので、意識せずにRを起動した場合に使うのはこれだと思います。上記プログラムの4行目のmean_bを4回変更し、同じファイル名だと上書きされてしまうのでこれも同じように(例えばfilenameを”result120.rds”、”result140.rds”、”result160.rds”、”result180.rds”)変更し、4回RGui上にプログラムをペーストすることによって実行する、これがシンプルですが、一番面倒な方法だと思います。
コマンドラインでの引数受け渡し
Unix、Linux、macOSでは標準的に使われるのかもしれませんが、Windowsではやや挙動が異なります。UNIX系では問題なく動作する(であろう)「R CMD BATCH」もWindows上では引数の受け渡しが上手く行かず、ウェブで検索をしてもあまりWindowsに特化した情報に辿り付くまでに相当に時間を要し、この記事でまとめようと思った動機でもあります。念の為「R CMD BATCH」では
R CMD BATCH program.R output.log --slave --vanilla
辺りで起動できます。vanillaオプションは、ハーゲンダッ、ではなくて、「–no-save, –no-restore, –no-site-file, –no-init-file, –no-environ」を同時に設定するオプションとのことです。Windows上での引数受け渡しの動作検証ができないので、コマンドラインではこれ以上の説明はしません。
Windows上でまともに引数の受け渡しが動作するのはRscript.exeの方です(R2.5.0から利用できるとのことです)。使い方としては、まずRのインストールしたディレクトリの中の、bin以下にpathを通します。64bit版を使うのであれば、例えば「C:\Program Files\R\R-x.x.x\bin\x64」(自身のバージョンを確認してR-x.x.xを補完)あたりをWindows10だとシステムのプロパティあたりでいじれる環境変数のPathに追加しておきます。次に、上のシミュレーションプログラムをちょっといじります。コマンドラインの引数は文字列として扱われるため、必要に応じて数値に変換します。
args <- commandArgs(TRUE) # TRUEで余計なものを除く niter <- 1000 nsub <- 10 mean_a <- 120 mean_b <- as.numeric(args[5]) sd <- 20 filename <- args[6] result <- numeric(niter) for(i in 1:niter){ dat_a <- rnorm(nsub, mean_a, sd) dat_b <- rnorm(nsub, mean_b, sd) result[i] <- t.test(dat_a, dat_b, var.equal=TRUE)$p.value } probsig <- sum(result < 0.05)/1000 saveRDS(probsig, filename)
これをsim.Rくらいの名前にして保存します。commandArgsにTRUEを与えずに実行すると、余計な引数も取れるため、取得できるargsの数が変わって後ろの引数を変更する必要があります。次に同じディレクトリで、上記プログラムを実行するためのバッチファイルを作ります。これはWindows上で動作するバッチファイルなので、Windowsのコマンドで書きます。とはいっても、ここでは単にRscriptを起動するだけです(–archオプションは省いても可です)。
Rscript.exe --arch x64 sim.R sim.log --slave --vanilla --args 120 result120.rds Rscript.exe --arch x64 sim.R sim.log --slave --vanilla --args 140 result140.rds Rscript.exe --arch x64 sim.R sim.log --slave --vanilla --args 160 result160.rds Rscript.exe --arch x64 sim.R sim.log --slave --vanilla --args 180 result180.rds pause
Rscript.exeでは、標準出力にoutputが出力されるため(それでもsim.logの指定は必要です)、実行が終わっても2秒間画面をそのままにするため、timeoutコマンドを実行しております。以上の実行が上手く行くと、同じディレクトリにresult120.rdsからresult180.rdsまでが作成されると思います。
環境変数による受け渡し
引数による受け渡しだと、Windowsだと動かなかったりすることもあり、またcommandArgsの動作によって修正が必要になったりと、色々と確認することが増えます。そこで、OS側の機能である環境変数を使ってデータの受け渡しを行う実装も試みました。こちらが私の場合は一番よくあっており、必要なところだけ修正で済むという利点があります。ただ、他のプログラムでも使われる環境変数をいじるため、多少気を付ける必要があります(恒久的にいじらないようにすれば問題はないとは思いますが)。一応、環境変数をWindows上のコマンドライン(Windows システムツールの中にあります)から確認するには「echo %varname%」としてやれば確認できます。
まず、プログラムを以下のように、以前はcommandArgsで取得していた部分をSys.getenv関数に置き換えます。
niter <- 1000 nsub <- 10 mean_a <- 120 mean_b <- as.numeric(Sys.getenv("mean_b")) sd <- 20 filename <- Sys.getenv("resultfile") result <- numeric(niter) for(i in 1:niter){ dat_a <- rnorm(nsub, mean_a, sd) dat_b <- rnorm(nsub, mean_b, sd) result[i] <- t.test(dat_a, dat_b, var.equal=TRUE)$p.value } probsig <- sum(result < 0.05)/1000 saveRDS(probsig, filename)
次に、これらを呼び出すWindows上のバッチファイルを以下のように作成します。環境変数はRから取得されると全て文字列として扱われますので、必要に応じて数値に変換します。Windowsのset関数に「環境変数=値」を与えることで、設定を行います。
set mean_b=120 set resultfile=result120.rds Rscript.exe --arch x64 sim.R sim.log --slave --vanilla set mean_b=140 set resultfile=result140.rds Rscript.exe --arch x64 sim.R sim.log --slave --vanilla set mean_b=160 set resultfile=result160.rds Rscript.exe --arch x64 sim.R sim.log --slave --vanilla set mean_b=180 set resultfile=result180.rds Rscript.exe --arch x64 sim.R sim.log --slave --vanilla
これで上のコマンドラインの引数と同じように動作すると思います。やや手順が増えましたが、今回は平均値とファイル名の両方を変更しているために2行必要ですが、共通するものは一度設定するだけでそのままにしても同じセッション(同じバッチファイル中)であれば使い回しできます。また、「Rscript.exe –arch x64 sim.R sim.log –slave –vanilla」の部分を「R CMD BATCH sim.R sim.log –slave –vanilla」としても全く同様に動作させることができます。その場合、ログがきちんとsim.logに保存されます。環境変数を使った受け渡しの方が、安定して使える印象があるため、私はこちらの方を普段は使っております。
最後に、バッチファイルにて設定を切り替えて、複数のバッチファイルを起動する際のtipsについて追加します。「%~n0」で、バッチファイルの拡張子を除いたファイル名を取得できます。これを「R CMD BATCH」と組み合せて使うと、
R CMD BATCH sim.R %~n0.log --slave --vanilla
にてログを自動的にバッチファイル名にすることが可能です。
コメント