Rでsocket

rsrubyとsocket

以前、Rをrubyから使うためにrsrubyを使ったことがある。しかし、debianのバージョンが上がったときに、うまくインストールできなくなったので、使うのを止めてしまった。しかし、もっと単純にrubyからRを使う方法を発見した。

Rの関数を調べていたら、socketConnectionというものを発見した。socketの読み書きをするためのものらしい。これを使えば、rubyと通信できるのではということで試してみた。

まずは、rubyをserverにして、Rをclientにする場合として、次のようなコードを書いた。まずはR側。

sock<-socketConnection(host = "localhost", 12343)
repeat{
  write("Hello, R server.",sock)
  str<-readLines(sock,1)
  eval(parse(text=str))
}

そして、ruby側。

require 'socket'
require 'thread'
s=TCPServer.new(12343)
Thread.start(s.accept){|cl|
begin
  i=0
  cl.each{|cmd|
    puts cmd
    cl.puts "plot(%d:%d,%d:%d)"%[i,i+10,i+10,i+20]
    i+=1
  }
ensure
  cl.close
end
} while true

Rで待ちを入れる関数を知らないので、ひたすらグラフを更新するが、一応うまく動く。次は逆にrubyをclientにして、Rをserverにする場合。Rでserverの処理を書くのは面倒かとも思ったが、意外に短くかける。

sock<-socketConnection(host = "localhost", 12343 ,server=TRUE)
repeat{
  cmd<-readLines(sock,1)
  eval(parse(text=cmd))
}

そして、rubyのclient。

require 'socket'
s=TCPSocket.open('localhost',12343)
i=0
loop{
  s.puts("plot(%d:%d,%d:%d)"%[i,i+10,i+20,i+30])
  i+=1
  sleep 5
}

Rのサーバーは命令を実行しても応答が帰って来ないが、clientが接続すると返ってくる。おそらくsingle connectionで、だからコードも短くかけるのだろう。

これで、Rとrubyをソケットでつないで、命令を実行できることが実証された。Rの実行結果を文字列で戻して、それをrubyで解釈すれば、実行結果を返すこともできるだろう。rsrubyの代わりに使おうと思えば、使える気がする。

しかし、問題はある。これはrsrubyも同じなのだが、plotで書いたグラフは、制御を奪われている間は更新されないようで、その上を別のwindowが通過すると、消えてしまう。これを回避する手段はないかな。

Read more...

データの場所の特定

Rのファイル操作
Rからファイルを読み込む際に、ファイルに余分なヘッダーがあると問題が生じる。これを避けるためには、例えばdata frameを読み込むときには、最初の何行かは除去するように指定することができる。しかし、様々な形式のファイルを扱うためには、最初の何行が余分なヘッダーかを判定する必要がある。Rでファイルから文字列を読み込む方法も分かって来たので、試しに書いてみた。

fl<-file("data.txt","r")
ttl<-""
repeat{
  num<-readLines(fl,1,ok=FALSE)
  if( regexpr("^s*[\\d\\.]",num,perl=TRUE)!=-1 ){break}
  ttl<-num
}
close(fl)
cat(ttl)
cat(num)

最初に数字かピリオドが来るまで一行ずつ読んで行くようにしてみた。データが無いときには、エラーが出るように、readLinesではok=FALSEとした。これで少しは扱えるファイルの種類が増えるかな。

Read more...

Rの特殊な関数

Rの関数への代入
Rの通常の関数は、x<-sqrt(2)のように使って、値を返す。しかし、attr(x,“class”)<-“name"のように、関数に代入しているように見えるような使い方ができる関数もある。このような関数は、以下のように定義することができる。

"test<-" <- function(x,value) x<-value^2
x<-1
test(x)<-2

この結果として、xには4は代入されることになる。ここで重要なのは、第二引数の名前をvalueにすることである。そうでないとエラーが生じる。これを応用すると、tklistboxのselectionをtclvalueを使って変更することが可能になる。

"tclvalue<-.tkwin" <- function(x,value){
  tkselection.clear(x,0,'end')
  tkselection.set(x,value)
}

このように定義しておけば、tclvalue(lb)<-3とすると、tklistboxの3番目が選ばれる。

Read more...

RのGUI

Rのグラフ作成支援

しばらくRネタが続いているが、その理由は、測定をしながらグラフを書くためのツールを作っていて、そのために必要なRのテクニックを学んでいたからだ。ようやく、多少は使えるものができたので、homepageに公開した。まあ、誰が使ってくれるわけでは無いとは思うが、測定用のPCにそのファイルを取ってくるときに、自分が便利にはなるだろう。

必要なルーチンは三つのファイルに分割した。一つは先に紹介したtktool.rで、tcltkを自分なりに使いやすくしたものだ。グラフの描画のデータ構造はplot.rに記述した。そして、GUI部分はgraphtk.rにまとめた。こうゆうプロクラムは、GUI部分が一番面倒である。実際、ファイルサイズも大きい。使うときには、

source("graphtk.rb")

として、出てきたメニューから使用する。以前使っていたigorに少しだけ影響を受けている。まだ最小限の機能しか使えないし、おそらくバグもあるだろう。imageやrglも機能限定ながら使えるようにしてみた。

このプログラムの前身として、rsrubyとrubytkを使って、rubyで書いたものがあった。昔の記録を見ると、2006年ぐらいには作っていたようだ。しかし、rsrubyでは描画したグラフが別のwindowが上を通ったときに消えたり、debianにrsrubyをうまくインストールできなかったり、という問題が生じてきて、あまり使えなかった。そして、2008年にRから直接tcltkを使ってGUIを作ろうと思って、書き始めてはいたが、Rではrubyのように思ったことが簡単に実現できないので、途中でしばらく放置してあった。最近、Rの知識も増えてきたので、思い出したように作っていたのだ。

ツールとしては使いやすくなったのだが、いろいろなグラフを一つのデータ構造で記述するには、なかなか工夫を必要とした。少し汚いやり方もしている。また、まだできないことも多い。上下に分割したグラフや、labelの位置調節など、コマンドラインからは簡単にできるのだが、それにGUIをつけるのは、非常に面倒だ。

一応beta versionが完成したので、しばらく使ってみて、気が向いたら機能を拡張していこう。

Read more...

オブジェクトの活用

Rとtcltk

Rでは、require(tcltk)とすれば、tkが使えるようになる。しかし、tkのコマンドはあまり馴染みが無いので、なかなか使いにくい。これが多少は使いやすくなるように、ツールを作って、個人的に利用している。しかし、気に入らない点がある。それは、tkで入力した値を取り出すときの方法が統一的ではないということである。tclVarのときには、tclvalue()で値を呼び出す。一方、tklistboxは、tkcurselection()を使って選ばれているものを取り出す。本当はどれでも同じ関数で値を取り出したい。

そこで、tclvalueを調べてみると、UseMethod("tclvalue")となっている。つまり、オブジェクトの種類によって、実行されるメソッドが違うのだ。そこで、attr(,"class")をつかってクラス名を調べると、tclVarはそのままtclVarで、tklistboxはtkwinとなっている。他のtkのオブジェクトもtkwinであるようだが、値を呼び出す必要があるのは、listboxだけなので、次のように定義した。

tclvalue.tkwin <- function(x) as.integer(tkcurselection(x))

こうすると、tclvalue()でtklistboxを呼ぶと、tkcurselection()が呼ばれて、値が取得できるのだ。

これで、tclvalue()のみで値の取得ができるようになった。残る問題は値の代入だ。tclVarはtclvalue(x)<-1などで値を設定できるが、当然tklistboxではだめだ。値を代入できるような関数をどのように書くかが分からない。一つの解決策としては、全く別のメソッドをつくってしまって、例えば、my_set(x,1)とすると、値が代入されるようにして、my_set.tclVarとmy_set.tkwinを定義する方法がある。しかし、tclvalue(x)<-1という形でできるようにできないのかな。

Read more...

オブジェクト指向言語R(uby)

Rのオブジェクトプログラミング

Rはオブジェクト指向の言語らしい。しかし、どのように書くとオブジェクト指向っぽくなるのかよく分からない。The R language definitionを少し読んで、どのように使うのかを調べてみた。

まず、オブジェクトのクラスを指定するためには、"class"という属性に文字列で指定するだけでよい。したがって、どんな名前のクラスにもできる。

a<-2
attr(a,"class")<-"num"
b<-"2"
attr(b,"class")<-"str"

次に、オブジェクト毎に、異なった挙動をするメソッドを定義する必要がある。これは、UseMethodを使って、関数名とオブジェクト名をピリオドでつないだ関数を自動的に呼ぶようにすることで実現する。

dub<-function(x) UseMethod("dub")
dub.default<-function(x) x
dub.num<-function(x) 2*x
dub.str<-function(x) paste(x,x,sep="")

こうすると、dub(a)を呼び出すと4が、dub(b)を呼び出すと"22"となる。

しかし、rubyのように、インスタンス変数を定義して、それに値を代入したり、いろいろなデータ構造を持たせるにはどのようにすれば良いのかよく分からない。Rのオブジェクト指向を使った良い例が見つかると分かりやすいのだが、まだ見つけていない。

Read more...

Rのベクトル

Rのdeparse()の挙動
deparse()をつかってプログラムを書いていたら、なんだか思ったように動かない。原因を調べていたら、長いデータをdeparse()すると、ベクトルになって返ってくることが原因だった。Rでは、ベクトルの処理は独特である。例えば、c(1,2,3,4)+c(4,5)は、5 7 7 9となり、c(1,2,3,4)+c(4,5,4,5)と解釈される。このような挙動のために、変になっていた。paste(deparse(),collapse="\n")で、一つの文字列にすると、問題なく動いた。

Read more...

オブジェクトの保存

Rのdeparse
Rのオブジェクトをファイルに保存する方法を考えていたのだが、deparse()を使うと良いようだ。

d<-list(1, 2, c(1, 2, 3))
deparse(d)

とすると、そのまま"list(1, 2, c(1, 2, 3))“となる。つまり、この頭に"d<-“をつければ、そのオブジェクトを作るコードが保存できることになる。なるほど。

Read more...

Rのオブジェクト

ベクトルとスカラー、リストとデータフレームの違い
Rはグラフソフトとして使っていて、これまで言語としてとらえていなかった。また、一貫して勉強したことが無いので、その言語の特徴をいまいち理解していない。しかし、くせはあって組みにくいけど、なかなかおもしろい言語のように思えてきたので、少しずつ勉強していけたらと考えている。 Rには様々なオブジェクトがあるが、どれだけの種類があるのだろう。オブジェクトの種類は、typeof()で調べることができる。 Rのオブジェクトにベクトルがあるが、これにはさらに五つの型があって、異なる型のデータを入れることはできない。つまり、c(1,“2”)とはできない。実は、スカラーもベクトルと考えているようだ。‘1’[1]としたら"1"が返ってきたし、“1”==c(“1”)はTRUEとなる。 異なる型を配列にできるオブジェクトとしては、リストがある。また、それぞれの要素には成分名をつけることができるので、連想配列のように使うこともできる。例えば、d<-list(a=1,b=2)としておけば、d[[1]]でも良いが、d$aでもアクセスできる。ファイルからデータを読み込むときにつくるデータフレームにアクセスの仕方が似ていると思って、試しにデータフレームをtypeof()で調べてみたら、listとなった。つまり、データフレームはリストだったようだ。しかし、d<-list(a=c(1,2),b=3)とすると、d$bは当然3になるが、d<-data.frame(a=c(1,2),b=3)とすると、d$bはc(3,3)となる。厳密には多少違うようだ。 まだまだ勉強する必要がありそうだ。

Read more...

R言語

Rの環境

Rでグラフを書きながら、測定の様子を観察していると、待っているときに、Rで楽にグラフが書けるようにRをいろいろといじってしまう。言語としてのRは、それなりに興味深い仕様になっている。

関数を定義すると、その中で定義された変数はローカルになる。しかし、外の変数を読むこともできるので、その変数がどの変数なのかが分からなくなってしまう。変数をすべてグローバルにしてしまえば、ややこしくはなくなるが、どうしても変数名が重複する可能性が出てくるので、変数はローカルであるべきだ。

次のような例を考えてみよう。

x<-1
test<-function(){
  cat(x)
  x<-2
  cat(x)
}
test()
cat(x)

この実行結果は121となる。testという関数が呼ばれて、最初にxを見ると、関数の外で定義されたxの値となり、関数の中で代入するとその値になる。そして関数の外で見ると、元の値になっている。つまり、関数の中の一個目と二個目のxは別のxになっているのである。

こうなってくると、関数から外の変数の値が見えるのが、便利なのか不便なのかが分からなくなってくる。

このような場合には、関数内だけの環境を作って、その環境を指定して変数に代入したり呼び出したりすればよい。長くなるけど、こんな感じになる。

x<-1
test<-function(){
  cat(x)
  testenv<-new.env()
  assign("x",2,env=testenv)
  cat(get("x",env=testenv))
}
test()
cat(x)
これで、xの意味合いがはっきりとする。しかもtempenvは関数の中のローカル変数なので、外からは見えない。でも、面倒だな。
Read more...