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」にアクセス。 以下のような画面が表示されたら成功。

f:id:Yasaichi:20140202013513p:plain

追記(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の番号