※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

第5章 RSRuby の拡張

ほとんどの簡単なアプリケーションでは基本の変換モードで十分ですが、 R オブジェクトを使うなら基本タイプを超えていけます。 PROC_CONVERSION and CLASS_CONVERSION モードではじめるのに必要でしょう。カスタム Ruby クラスと連携してほんとに強力なシステムを作ることが出来ます。

5.0.1 Enhanced RObj

RPy マニュアルのデモと同様な RObj クラスの拡張例を示します。 R オブジェクトを探す属性は method_missing を使うよう置き換えています。また、R によって出力された文字列を置換するメソッドのデモも示します。 This code is included in the RSRuby distribution and can be activated by require-ing rsruby/erobj and setting the proc table appropriately as shown:

class ERObj
  @@x = 1
  def initialize(robj) 
    @robj = robj
    @r = RSRuby.instance
  end
The ERObj initialization method simply stores the wrapped RObj and the RSRuby interpreter.
  def as_r
    @robj.as_r
  end
  def lcall(args)
    @robj.lcall(args)
  end
The as_r and lcall methods simply delegate to the same methods in the wrapped underlying RObj.
  def to_s
    @@x += 1
    mode = RSRuby.get_default_mode
    RSRuby.set_default_mode(RSRuby::NO_CONVERSION)
    a = @r.textConnection("tmpobj#{@@x}",’w’)
    RSRuby.set_default_mode(RSRuby::BASIC_CONVERSION)
    @r.sink(:file => a, :type => ’output’)
    @r.print_(@robj)
    @r.sink.call()
    @r.close_connection(a)
    str = @r["tmpobj#{@@x}"].join("\n")
    RSRuby.set_default_mode(mode)
    return str
  end

The to_s method makes the R interpreter print to the tmpobj variable using the textConnection and sink functions. This is then retrieved and returned as the string representation of the object for Ruby.

  def method_missing(attr)
    mode = RSRuby.get_default_mode
    RSRuby.set_default_mode(RSRuby::BASIC_CONVERSION)
    e = @r[’\$’].call(@robj,attr.to_s)
    RSRuby.set_default_mode(mode)
    return e
  end
end

The method missing function returns the attribute with the same name as the missing method from the wrapped RObj. To use the ERObj class we can set the proc table to return a new ERObj with every conversion.

irb> r = RSRuby.instance
  => #<RSRuby:0xb7baf320>
irb> r.proc_table[lambda{|x| true}] = lambda{|x| ERObj.new(x)}
  => #<Proc:0xb7ba68ec@(irb):2>
irb> RSRuby.set_default_mode(RSRuby::PROC_CONVERSION)
  => 4

To test the returned class we use the R t.test function, which returns an R list. Note the string representation of the returned object which matches the string form given by R.

irb> e = r.t_test([1,2,3,4,5,6])
  => #<ERObj:0xb7b9d918>
irb> puts e One Sample t-test
     data: c(1, 2, 3, 4, 5, 6)
     t = 4.5826, df = 5, p-value = 0.005934

alternative hypothesis: true mean is not equal to 0 95 percent confidence interval: 1.536686 5.463314 sample estimates:

mean of x 3.5
  => nil
irb> e.statistic[’t’]
  => 4.58257569495584


5.0.2 ArrayFields

The default conversion mode converts R lists into Ruby Hashes. This changes the seman- tics of the returned object because R lists retain order information while Ruby Hashes are unordered. To fix this we can plug a new method in to return Arrays extended by the ArrayFields gem:

require ’rubygems’
require_gem ’arrayfields’
require ’rsruby’
test_proc = lambda{|x| !(RSRuby.instance.attr(x,’names’).nil?)}

This Proc tests the given object to see if the names attribute is set. If so, the following Proc is used to convert the object.

conv_proc = lambda{|x|
hash = x.to_ruby
array = []
array.fields = RSRuby.instance.attr(x,’names’)
RSRuby.instance.attr(x,’names’).each{|f| array[f] = hash[f]}
return array
}

We then setup the proc table with these procs and test using the R t.test function.

r = RSRuby.instance
r.t_test.autoconvert(RSRuby::PROC_CONVERSION)
r.proc_table[test_proc] = conv_proc
r.t_test([1,2,3]).each_pair{|f,v| puts "#{f} - #{v}"}

Note that the point here is that the list returned by t.test is converted to an Array (with the Arrayfields extensions), which retains order information unlike the Hash it would be converted to otherwise.


5.0.3 DataFrames

DataFrames は R プログラミングでは有用なオブジェクトです。