RSRubyでRをRubyから使う
RubyからRを使うRSRubyの使い方を説明します。3年ぐらい前から使っているのですがなかなか高速でいいです。
まずはインストール方法から。環境は以下の通りです。
- Windows 7 SP1
- R version 3.0.1 (2013-05-16)
参考ページはこちら(金子先生のホームページは役立つ情報が満載です)。 rubyとrsrubyは以下のバージョンをインストールしました。
- RubyInstallerをinstallします。(official)
- Development Kit(DevKit) もinstallします(参考)
- フォルダ作ってその中に解凍
- rubyのインストールディレクトリに解凍してできたファイルを上書きコピー
- 以下のコマンドを実行
cd C:\ruby\Ruby200 ruby dk.rb init vi config.yml # rubyのインストール先が正しく認識されなかった時に ruby dk.rb install
- gemでrsrubyをインストール
gem install rubygems-update gem install rsruby -- --with-R-dir=C:/R/R-3.0.1 --with-opt-dir=C:/R/R-3.0.1/share/R --with-R-lib=C:/R/R-3.0.1/bin/i386 --with-R-include=C:/R/R-3.0.1/include
- 環境変数PATHに「C:\R\R-3.0.1\bin\i386;」を追加
次に使い方です。
require 'rsruby' require 'rsruby/dataframe' rr = RSRuby.instance rr.class_table['data.frame'] = lambda{|x| DataFrame.new(x)} RSRuby.set_default_mode(RSRuby::CLASS_CONVERSION) # RubyのArrayを渡す res = rr.pairwise_t_test([1.1, 2.2, 3.3, 4.4, 7.7, 8.8, 9.9, 11.0], [1,1,1,1,2,2,2,2], {:'p.adjust.method' => 'bonferroni'}) p res #=> {"method"=>"t tests with pooled SD", "data.name"=>"c(1.1, 2.2, 3.3, 4.4, 7.7, 8.8, 9.9, 11) and c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L)", "p.value"=>[0.0005947649754862591], "p.adjust.method"=>"bonferroni"} p res["p.value"].first #=> 0.0005947649754862591 # Rubyでdata.frame (DataFrameクラス) を作る. df1 = rr.as_data_frame(:x => {'data' => [1.1, 2.2, 3.3, 4.4, 7.7, 8.8, 9.9, 11.0], 'group' => [1,1,1,1,2,2,2,2]}) puts df1.columns.join(", ") #=> data, group puts df1.rows.join(", ") #=> 1, 2, 3, 4, 5, 6, 7, 8 # [オススメしません] Rの関数を対応するRubyの関数で呼び出す. # Rの関数名の'.'を'_'に置き換える. parameterとしてHashを取る. df1 = rr.as_data_frame(:x => {'data' => [1.1, 2.2, 3.3, 4.4, 7.7, 8.8, 9.9, 11.0], 'group' => [1,1,1,1,2,2,2,2]}) res = rr.pairwise_t_test(df1.data, df1.group, {:'p.adjust.method'=>'bonferroni'}) # [オススメです] Rの関数をベタ書きで呼び出す. df1 = rr.as_data_frame(:x => {'data' => [1.1, 2.2, 3.3, 4.4, 7.7, 8.8, 9.9, 11.0], 'group' => [1,1,1,1,2,2,2,2]}) rr.assign('df1', df1) res = rr.eval_R("pairwise.t.test(df1$data, df1$group, p.adjust.method='bonferroni')") # Rで作ったdata.frameをRubyで受け取る (Rコードの最後の返り値を受け取る) df1 = rr.eval_R <<-R_COMMAND data <- c(1:4, 7:10) * 1.1 group <- c(rep(1,4), rep(2,4)) data.frame(data, group) R_COMMAND puts df1.to_s # => # data group # 1 1.1 1 # 2 2.2 1 # 3 3.3 1 # 4 4.4 1 # 5 7.7 2 # 6 8.8 2 # 7 9.9 2 # 8 11.0 2 # randomForestを使う例 rr.eval_R <<-R_COMMAND library(randomForest) data(iris) iris.rf <- randomForest(formula = Species ~ ., data = iris) save(iris.rf, file = "model.RData") R_COMMAND iris_new = rr.as_data_frame(:x => { 'Sepal.Length' => [6.1, 6.4, 8.0], 'Sepal.Width' => [3.3, 3.0, 2.8], 'Petal.Length' => [1.3, 3.2, 5.5], 'Petal.Width' => [0.3, 1.5, 2.2] }) rr.assign('iris.new', iris_new) predict = rr.eval_R <<-R_COMMAND library(randomForest) load("model.RData") predict(iris.rf, newdata = iris.new, type = 'prob') R_COMMAND p predict #=> [[0.932, 0.068, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]
ソースコードの通りです。Rのベタ書きをメインに使うのがオススメです。
eval_Rの内側だけRのsyntax highlightして欲しいのですがそのへんに転がっているエディタでは難しいですよね。かといって [オススメしません] のところにあるようにruby上に名前が変換された関数を使おうとすると、昔は関数のオプションが文字列をキーとしたHashだったのに、シンボルをキーとしたHashに変更されていたりして戸惑うことがありました。Rに詳しい人にとって可読性が落ちるというのもいただけない点です。
また、rubyのNArrayはそのまま渡せないのでto_aで配列化する必要があります。NArrayをバリバリ使っている人にはやや残念です。