スキップしてメイン コンテンツに移動

RubyからRを使うRinRubyを試してみた

Ruby から R へアクセスできる RinRuby について日本語の文章があまりないみたいなので書く。

今回の環境は僕が常用している Mac OS X 10.6.4 と R 2.11.1, Ruby 1.9.2, RubyGems 1.3.7です。Ruby 1.8系でも動きそうですが、まさか、まだ 1.8 系使っているとか、ありえないですよねー、まさかねー。

まず RinRuby をインストールするよ。
[code]
sudo gem install rinruby
[/code]

すごく簡単。適当にあることないことコードを書く。

[ruby]
#!/usr/bin/env ruby

require 'rubygems'
require 'rinruby'
require 'pp'

sample_size = 100
hist_file = "/Users/itoshi/Projects/rinruby/hist.png"

# うざいメッセージを止める
R.echo(enable = false)

# pull メソッドで R コードの実行結果を受けとる
R.x = R.pull "rnorm(#{sample_size})"

# 関数も問題なく使える
R.x_sum = R.pull "sum(x)"
R.x_sd = R.pull "sd(x)"

# Ruby で出力する
puts R.x_sum
puts R.x_sd

# 関数のように数行のときはヒアドキュメントを使う
R.eval <<EOF
myfactorial <- function(n) {
if (n <= 1)
return(1)
else
return( n * Recall(n-1) )
}
fac <- myfactorial(#{sample_size})
EOF

# Rでは fac という変数は、Ruby からは R.fac でアクセスできる
puts R.fac

# plot もできる
# export DISPLAY=localhost:0.0 して X11 の起動を忘れずに (Mac)
R.eval <<EOF
png("#{hist_file}")
hist(x)
dev.off()
EOF
[/ruby]

ローカルに hist.png ができているはず。

さてどういう仕組みになっているのだろうか? RinRuby インスタンスを除いてみよう。
[ruby]
irb(main):001:0> require "rinruby"
=> true
irb(main):002:0> require "pp"
=> true
irb(main):003:0> pp RinRuby.new
#<RinRuby:0x00000100a58380
@echo_enabled=true,
@echo_stderr=false,
@engine=#<IO:fd 18>,
@executable="R",
@hostname="127.0.0.1",
@interactive=true,
@opts=
{:echo=>true,
:interactive=>true,
:executable=>nil,
:port_number=>38442,
:port_width=>1000,
:hostname=>"127.0.0.1"},
@platform="default",
@port_number=39093,
@port_width=1000,
@reader=#<IO:fd 18>,
@readline="constant",
@server_socket=#<TCPServer:fd 15>,
@socket=#<TCPSocket:fd 16>,
@writer=#<IO:fd 18>>
=> #<RinRuby:0x00000100a58380 @opts={:echo=>true, :interactive=>true, :executable=>nil, :port_number=>38442, :port_width=>1000, :hostname=>"127.0.0.1"}, @port_width=1000, @executable="R", @hostname="127.0.0.1", @port_number=39093, @server_socket=#<TCPServer:fd 15>, @echo_enabled=true, @echo_stderr=false, @interactive=true, @platform="default", @readline="constant", @engine=#<IO:fd 18>, @reader=#<IO:fd 18>, @writer=#<IO:fd 18>, @socket=#<TCPSocket:fd 16>>
[/ruby]

なにやら TCP という怪しい文字列が! RinRuby は 800行程度の Pure Ruby で書かれているようです。のぞいてみましょう。どきどき。

RinRuby のコンストラク部分の抜粋です。
[ruby]
while true
begin
@port_number = @opts[:port_number] + rand(port_width)
@server_socket = TCPServer::new(@hostname, @port_number)
break
rescue Errno::EADDRINUSE
sleep 0.5 if port_width == 1
end
end
@echo_enabled = @opts[:echo]
@echo_stderr = false
@interactive = @opts[:interactive]
@platform = case RUBY_PLATFORM
when /mswin/ then 'windows'
when /mingw/ then 'windows'
when /bccwin/ then 'windows'
when /cygwin/ then 'windows-cygwin'
when /java/
require 'java' #:nodoc:
if java.lang.System.getProperty("os.name") =~ /[Ww]indows/
'windows-java'
else
'default-java'
end
else 'default'
end
if @executable == nil
@executable = ( @platform =~ /windows/ ) ? find_R_on_windows(@platform =~ /cygwin/) : 'R'
end
platform_options = []
if ( @interactive )
begin
require 'readline'
rescue LoadError
end
@readline = defined?(Readline)
platform_options << ( ( @platform =~ /windows/ ) ? '--ess' : '--interactive' )
else
@readline = false
end
cmd = %Q<#{executable} #{platform_options.join(' ')} --slave>
@engine = IO.popen(cmd,"w+")
@reader = @engine
@writer = @engine
raise "Engine closed" if @engine.closed?
@writer.puts <<-EOF
#{RinRuby_KeepTrying_Variable} <- TRUE
while ( #{RinRuby_KeepTrying_Variable} ) {
#{RinRuby_Socket} <- try(suppressWarnings(socketConnection("#{@hostname}", #{@port_number}, blocking=TRUE, open="rb")),TRUE)
if ( inherits(#{RinRuby_Socket},"try-error") ) {
Sys.sleep(0.1)
} else {
#{RinRuby_KeepTrying_Variable} <- FALSE
}
}
rm(#{RinRuby_KeepTrying_Variable})
EOF
r_rinruby_get_value
r_rinruby_pull
r_rinruby_parseable
@socket = @server_socket.accept
echo(nil,true) if @platform =~ /.*-java/ # Redirect error messages on the Java platform
[/ruby]

Rの起動は、IO.popen, つまりOSのパイプで、Ruby と Rのデータのやり取りは TCP/IPストリーム型接続で行うという面白い仕組みになっています。始めにソケットを用意しています (4行目)。次に、プラットフォームごとに、Rを起動するコマンドを生成してパイプで開いていますね (13-42)。最後に @server_socket.accept で接続を受けとっています。Ruby がサーバ、Rがクライアントということです。

RSRuby など、RとタイトカップリングしているCコードだとメンテが大変で、Windows とか提供されてないよね。だからこういう仕組みにしたんだよ、というのが作者の主張のようです。RinRubyの論文はこちら (PDF)

History.txt をみると Ruby 1.9 への対応がされていたり、最終更新日が2010/05/01 だったりとちゃんとメンテされているっぽいですね。

まとめ


インストールも簡単だし、使い方もそんなに難しくないね。ちょこっとR側の関数を使いたいときに気軽に使えそうな予感。ただ、Ruby 書いているのに、= が <- になるバグが頻出するw

あれ、気付いたら R package じゃなくて Ruby 読んでたわw 連載のほうもぼちぼちのんびりペースでアップしていきます。

コメント

このブログの人気の投稿

シーケンスアダプタ配列除去ツールまとめ

FASTQ/A file からシーケンスアダプター配列やプライマー配列を除くためのプログラムをまとめてみる。 まず、配列の除去には大別して2つの方向性がある。ひとつは、アダプター配列を含む「リード」を除いてしまう方法。もうひとつは除きたい配列をリードからトリムする方法である。後者のほうが有効リードが増えるメリットが、綺麗に除ききれない場合は、ゲノムへのマップ率が下がる。 気をつける点としては、アダプター/プライマーの reverse complement を検索するかどうか。paired end の際には大事になる。クオリティでトリムできるものや、Paired-end を考慮するものなどもある。アダプター/プライマー配列の文字列を引数として直接入力するものと、multi fasta 形式で指定できるももある。 From Evernote: シーケンスアダプタ配列除去ツールまとめ TagDust http://genome.gsc.riken.jp/osc/english/software/src/nexalign-1.3.5.tgz http://bioinformatics.oxfordjournals.org/content/25/21/2839.full インストール: curl -O http://genome.gsc.riken.jp/osc/english/software/src/tagdust.tgztar zxvf tagdust.tgz cd tagdust/ make sudo make install rehash 使いかた: tagdust adapter.fasta input.fastq -fdr 0.05 -o output.clean.fastq -a output.artifactual.fastq 解説: 入出力形式は fastq/a が使える。リード全体を除く。速い。アダプター配列を fasta 形式で入力できるのが地味に便利で、これに対応しているものがなかなかない。Muth–Manber algorithm (Approximate multiple

DNAを増幅するサーマルサイクラーを自作してみたよ

DNAをPCR法で増幅するために必要なサーマルサイクラーを自作してみました。自作と言っても、いわゆる、PCの自作と同じでパーツを組み立てていく感じです。購入から組み立ての様子を簡単に紹介します。 モチベーション ラボには様々なレクリエーションがあります。例えば、単にどこかに遊びに行ったり、スポーツ大会したり、ひたすら合宿形式でプログレスのプレゼンをするミーティングするなどがあります。それもよいのですが、せっかくなので、普段の研究時間ではトライできないが、研究に関わる hack を行う、というイベントを企画してみました。夏休みの自由研究や社会科見学的なノリです。   うちのラボでは、PCRを使ったウェットの実験技術の開発をしてきました。しかし、サーマルサイクラーのハードウェアの仕組みを体験的に理解している訳ではありません。そこで、サーマルサイクラーを作ってみました。   欧米で始まっている、自宅のガレージやキッチンでバイオロジーを行うムーブメント、バイオパンク、DIYbio を体験しておきたいというのもありますし、Arduino などオープンハードウェア、Maker のムーブメントを体験するのも目的の一つです。ハードウェア開発が思っているほどハードルが下っていることを体験できて、かつ、将来、ウェットの開発だけでなく、装置開発などもできたら、ラッキー、ぐらいの気持ちでやってみました。   購入 今回作ったのは、組み立て式で、かつ、仕様などや設計図が公開されているOpenPCRというサーマルサイクラーです。ハードウェアの仕様・設計図、制御ソフトウェアなどの情報がすべて公開されており、部品からも自作することが可能です。今回は、「設計図から部品や回路のパーツを作り、それらを組み立てる直前のもの」を購入しました。   ChaiBio https://www.chaibio.com/   OpenPCR https://www.chaibio.com/products/openpcr   なぜか http://openpcr.org/  で購入できなかったので、eBay にある ChaiBio で買いました。   OpenPCR - eBay http://www.ebay.com/itm/111096418574   本体価格は

大学の研究室でアカデミックプランが使えるICTツール

自分らでサーバ管理したくないので、SaaS系とローカルで動くソフトのみ。ローカルで動くソフトに関しては、Mac or Docker で動くもののみ。 無償 G Suite for Education  (ドキュメント共有、カレンダーなど) GitHub Education  (ソースコード管理) esa.io アカデミックプラン  (知識共有) Tableau  (データ可視化) Scrapbox  (知識共有) GROWI.cloud  (Wikiなど) 割引 Slack の教育支援プログラム  (ビジネスチャット) Dropbox Education  (ファイル共有、ドキュメント共有) Office 356  (オフィスソフト) Adobe Creative Cloud  (画像編集) AutoDesk for Education  (CADなど) これから申し込んでいくところなので、本当に使えるかはわかりせん。使えた使えないなどの情報やほかのツールでお勧めがあれば教えてもらえると嬉しいです。 アカデミアでなくても無料で使えるツールのうち、うちで使うであろうものは以下に列挙していく。 Google Colaboratory  (データ解析) Overleaf  (論文執筆) Rstudio  (開発, データ解析) VS code (開発)