Rのバグ取り

Rのバグの原因
まだ、Rを少しずついじっているが、プログラムを組んでいるといろいろとバグが見つかる。Rは比較的くせが強いので、慣れないせいでバグが生じてしまうのであろう。 まず面倒なのが、indexが1から始まるという点だ。関数の引数では0を取るものもあるので、いろいろとややこしい。+1をする必要がある場合と無い場合があり、これがバグを引き起こすときがある。 次に問題になるのが、関数によっては、引数にベクトルを渡すとベクトルが返ってくる場合があるためである。例えば、is.na(1)とするとFALSEとなるが、is.na(c(1,NA))とするとc(FALSE,TRUE)となる。c(1,NA)はNAではないので、FALSEを返して欲しいのだが、そうするためにはどうしたら良いのか分からない。all(is.na(c(1,NA)))とか、is.na(c(1,NA))[1]とすれば、今の例では良いのだが。複雑なデータ構造を使う場合には、これが問題になる。 あとは、ベクトルの連結も少し奇妙な挙動をする。c(c(1,2),3)はc(1,2,3)となり、list(list(1,2),3)はそのままだ。しかし、c(list(1,2),list(3))はlist(1,2,3)となる。c(list(1,2),3)でもlist(1,2,3)となる。この二つの結果が一致するのは変な気がする。そして要素を取り出すときには、、c()は[]を、list()は[[]]を使う。だんだん訳が分からなくなってくる。 他にもいろいろとあるだろうが、このあたりの感覚が、他の言語と少し変わっていて、つい好ましくないコードを書いてしまってバグが生じやすくなっている気がする。さらに、エラーメッセージも親切では無いので、バグ取りもなかなか難しい。もう少し慣れないといけないな。

Read more...

XPの販売終了

測定系に用いるOS
自作の測定装置は、できるだけLinuxで構築するようにしている。現在は測定にWindowsを用いる人が多いようで、Linuxでシステムを構築するためには、情報も少ないために、慣れていない場合には時間がかかるだろう。しかし、長期的な使用を考える場合には、Linuxの方が優れているように思う。 とうとう、WindowsXPも販売終了するようだ。XPで動いている測定システムは結構あると思うが、今後それらはどうなるのか心配になる。Windows98でないと動かないような測定システムも存在するが、それを使っている人はすでに困っているらしいが、その問題が今度はXPで起ころうとしている。メーカーがOSの切り替えをサポートしてくれればよいが、当然コストはかかるし、サポートが期待できない場合もある。 研究室にある古いWindowsの測定システムの一部は、LinuxのWine上で動かすことに成功して、現在は安定して満足している。幸運だったのは、それがシリアルポートしか使っていなかったからである。Wineのversionによっては動かなかったが、GPIBなどを使わなければいけない場合にはどうすれば良いのだろう。

Read more...

GPIBからRS232Cへ

RS232Cでの制御の難しさ
普段、GPIBで制御している装置を、RS232Cで制御する必要があって、プログラムを書き換えていたが、意外に苦労してしまった。ボーレートやパリティの設定などは当然として、他にもいろいろと変えないといけないことが分かった。 あくまで、今回の装置に関してだが、以下のような変更をした。まず、命令の後にリターンコードをつけないといけない。GPIBだと、データの終了を示す信号があるので、区切りが分かるが、RS232Cだとその代わりにリターンコードを使う。次に、リモートモードへの移行コマンドを実行する必要があった。GPIBではRENラインがその役割をしてくれているのかも知れない。そして、writeとreadの間にwaitを入れる必要があった。GPIBではhand shakeをしているので、問題がないが、データが準備できていない時に読み出しに行くと、良くないのだろう。 一瞬でプログラムを書き上げるつもりだったが、つまらないこれらの問題点を発見するまでに、一時間ぐらいかかってしまった。

Read more...

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...