R on Rails with Rserve
概要
RをRailsで動かすまでの簡単なチュートリアル。
誰かの役に立つかもしれないと思って書くことにした。
そもそもRをRubyで動かすには
主なライブラリが3つある。
- RSRuby
実行速度は3つの中で最も速いらしいが、パスを通さないとだめだったり、
その他実行までにいくつかのハードルあり。
- RinRuby
扱えるデータ型がベクトルと配列のみなため却下。実行速度もこの中では最も遅い。
ただ、インストールは簡単。Rails上でも実行できた。
- Rserve(Rserve-Ruby-client)
今回用いたもの。実行速度は上の2つの間。
まとめるとこんな感じ。より詳しい長所・短所については以下を参照のこと。
Ruby and R
最初RSRubyから試してみたものの、Rails上で動かしたときにC stack usage is too close to the limit
というエラーが出て、rubyforgeのここを参考にスタックの上限をいじってみるが解決せず。
とゆうわけでRserveを試すことに。
実行環境
導入
以下順に説明していく。
Rからパッケージ「Rserve」をインストール
Rを起動して以下のコマンドを入力。
install.packages("Rserve")
インストール後
library()
を実行して出てくるパッケージ一覧の中にRserveがあればOK。
Rubyからライブラリ「Rserve-Ruby-client」をインストール
ターミナル上で以下のコマンドを入力。
gem install rserve-client
インストール後
gem list
を実行して出てくるライブラリ一覧の中にrserve-clientがあればOK。
Railsから実行
ここでは、ヒストグラムを表示する簡単なアプリを作成する。
まずはテスト用のアプリを作成。
rails new test_app
Gemfileのどこかに
gem 'rserve-client', require: 'rserve'
を追加して、bundle install
を実行。次に
rails g controller page test
で、適当なコントローラーを作成したら、/app/cotrollers/page_controller.rb
を編集して
# encoding:UTF-8 class PageController < ApplicationController def test c = Rserve::Connection.new # ルートディレクトリのパスをRへ c.assign("root", Rails.root.to_s) # サンプルコード c.eval <<-EOF # 標準正規分布に従う乱数の発生 x = rnorm(100,0,1) # ヒストグラムを作成して保存 png(paste(root, "/app/assets/images/test.png", sep="")) hist(x) dev.off() EOF end end
として保存。次に/app/views/page/test.html.erb
を編集して
<h1>R on Rails with Rserve</h1> <%= image_tag 'test.png' %>
として保存。最後に
rails s
でサーバーを起動し、「http://localhost:3000/page/test」にアクセス。 以下のような画面が表示されたら成功。
追記(2013/2/26)
このままだとあらかじめRserveを起動しておかないとRserve::Connection::RserveNotStartedError
になってしまう。
そこで、Railsの初期化処理後にRserveを起動するように設定する。
これには、/config/environments/development.rb(or production.rb
に以下を追加すればよい。
# rserveの起動 config.after_initialize do rserve_port = 6311 rserve_path = "/Library/Frameworks/R.framework/Resources/library/Rserve/libs/Rserve" system("R CMD #{rserve_path} --RS-port #{rserve_port} --slave") end
なお、ポート番号はデフォルトで6311となっている。変更する場合は上記のコードのrserve_port
の値を変更すればよい。
また、Rserveを終了する場合は、ターミナルで
lsof -i:6311
と入力して出てきたRserveのPIDを以下のように指定すればよい。
kill -9 PIDの番号