Debian GNU/Linux 5.0.6
本日、久々にaptitude update; aptitude upgradeしたら、100以上のパッケージが入れ替わった。なぜこんなに多いんだろうと思ったら、9/4にDebian GNU/Linux 5.0.6がリリースされていたからだった。おそらく、あと半年ぐらいすれば、squeezeがリリースされると思うが、Debianもここ数年で、ますます使いやすいものになってきた。素人向けになったとも言えるが。一方、多くのユーザーを抱えるWindowsは、2000の頃からあまり変わった気がしない。サーバとしてはともかく、クライアントとしてはある程度使い易いものになっているので、見た目以外は大きく変化しないのかも知れないが、安定性の低さもあまり変わっていないように思う。しかし、Linuxユーザーはあまり増えている気がしない。個人で使うときの使いやすさからすれば、Windowsとそれほど変わらないと思うのだが、他の人とデータのやり取りをしたり、プリンターなどのメーカーがLinuxのサポートをしていない外部の機器を使うときには、不便を感じるだろう。しかし、これは、ユーザーの数が少ないからそうなるので、ユーザーが多くなれば解決すると思うのだが。未だに身近にLinuxユーザーはほとんどいない。Macユーザーはいるんだけど。
ssh server
Mac OSXのssh
linuxを使っていると、sshで別のマシンに入って作業をすることがある。Windowでは、時代遅れのtelnetは使えても、sshは標準では使えない。windowsを使っていた頃は、cygwinのsshを使っていた。
debianでは、ssh serverは標準ではインストールされない設定になっている。いくつか前のsargeとかでは、たしか標準でインストールされてしまっていたので、動かさないように設定することもあった気がする。
BSDのMac OSXではどうなのだろうと思って調べてみたら、設定でリモートログインを許可すると、ssh serverが働く用になっているらしい。
線形回帰と多項式回帰
Rの多項式fit
Rの直線での回帰は、次のように簡単にできる。
x<-c(1,2,3,4,5) y<-c(1,4,8,11,18) plot(x,y) fit1<-lm(y~x) abline(fit1)
しかし、多項式fitは面倒である。以前は、次のようにしていた。
fit2<-lm(y~x+I(x^2))
当たり前なのだが、つぎのようにしてもできるらしい。
x2<-x^2 fit3<-lm(y~x+x2)
実際に使うときには、どちらが良いのだろう。メモリを食わないという意味では、前者の方が良いような気もするし、後者の方が計算コストが少ない気もする。
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()は[[]]を使う。だんだん訳が分からなくなってくる。
他にもいろいろとあるだろうが、このあたりの感覚が、他の言語と少し変わっていて、つい好ましくないコードを書いてしまってバグが生じやすくなっている気がする。さらに、エラーメッセージも親切では無いので、バグ取りもなかなか難しい。もう少し慣れないといけないな。
XPの販売終了
測定系に用いるOS
自作の測定装置は、できるだけLinuxで構築するようにしている。現在は測定にWindowsを用いる人が多いようで、Linuxでシステムを構築するためには、情報も少ないために、慣れていない場合には時間がかかるだろう。しかし、長期的な使用を考える場合には、Linuxの方が優れているように思う。
とうとう、WindowsXPも販売終了するようだ。XPで動いている測定システムは結構あると思うが、今後それらはどうなるのか心配になる。Windows98でないと動かないような測定システムも存在するが、それを使っている人はすでに困っているらしいが、その問題が今度はXPで起ころうとしている。メーカーがOSの切り替えをサポートしてくれればよいが、当然コストはかかるし、サポートが期待できない場合もある。
研究室にある古いWindowsの測定システムの一部は、LinuxのWine上で動かすことに成功して、現在は安定して満足している。幸運だったのは、それがシリアルポートしか使っていなかったからである。Wineのversionによっては動かなかったが、GPIBなどを使わなければいけない場合にはどうすれば良いのだろう。
GPIBからRS232Cへ
RS232Cでの制御の難しさ
普段、GPIBで制御している装置を、RS232Cで制御する必要があって、プログラムを書き換えていたが、意外に苦労してしまった。ボーレートやパリティの設定などは当然として、他にもいろいろと変えないといけないことが分かった。
あくまで、今回の装置に関してだが、以下のような変更をした。まず、命令の後にリターンコードをつけないといけない。GPIBだと、データの終了を示す信号があるので、区切りが分かるが、RS232Cだとその代わりにリターンコードを使う。次に、リモートモードへの移行コマンドを実行する必要があった。GPIBではRENラインがその役割をしてくれているのかも知れない。そして、writeとreadの間にwaitを入れる必要があった。GPIBではhand shakeをしているので、問題がないが、データが準備できていない時に読み出しに行くと、良くないのだろう。
一瞬でプログラムを書き上げるつもりだったが、つまらないこれらの問題点を発見するまでに、一時間ぐらいかかってしまった。
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が通過すると、消えてしまう。これを回避する手段はないかな。
データの場所の特定
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とした。これで少しは扱えるファイルの種類が増えるかな。
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番目が選ばれる。
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が完成したので、しばらく使ってみて、気が向いたら機能を拡張していこう。