2011/06/27からのアクセス回数 5672
ここで紹介したSageワークシートは、以下のURLからダウンロードできます。
http://www15191ue.sakura.ne.jp:8000/home/pub/15/
また、Sageのサーバを公開しているサイト(http://www.sagenb.org/, http://www15191ue.sakura.ne.jp:8000/)にユーザIDを作成することで、ダウンロードしたワークシートを アップロードし、実行したり、変更していろいろ動きを試すことができます。
Rはフリーの統計解析ソフトで、Sageのパッケージに付属しており、SageからRのコマンドを実行するための インターフェースも用意されています。
Rの特徴に以下のものがあげられます。
SageからRのグラフ機能を使った例として、"R in action" で紹介されているグラフをSageで表示したSageのワークシート を ここ にアップしてありますので、 参考にしてください。
ここでは、SageからRのコマンドを使用する場合の注意点とRインタフェースの使用方法に説明します。
SageからRのコマンドを使いやすくするために、以下のユーティリティ関数を用意、RUtil.sageに納めました。
attach関数を使ってRUtil.sageを読み込みます。
sageへの入力:
# Rのユーティリティ関数を読み込む attach(DATA+'RUtil.sage')
sageへの入力:
# ユーティリティ関数は以下のコマンドで内容を確認できます(#を外して実行してください) printFile("RUtil.sage")
sageの出力:
# Safari以外ではPDFをimgタグで表示できないので、 # 外部コマンドImageMagickコマンドを使ってpngに変換するように変更 2012/06/27 # # Rのグラフをsageで表示するためのユーティリティ関数 import time def preGraph(pdfFile): filename = DATA+pdfFile r.pdf(file='"%s"' %filename) return pdfFile def offGraph(): r.dev_off() def postGraph(pdfFile, fac=0.75): r.dev_off() width = int(640*fac) # html('<img src="%s?%s" width="%spx">'%(pdfFile, time.time(), width)) pngFile = convertPdf2Png(pdfFile) html('<img src="%s?%s" width="%spx">'%(pngFile, time.time(), width)) def getGraph(pdfFile, fac=0.75): width = int(640*fac) # return '<img src="%s?%s" width="%spx">'%(pdfFile, time.time(), width) pngFile = convertPdf2Png(pdfFile) return '<img src="%s?%s" width="%spx">'%(pngFile, time.time(), width) def convertPdf2Png(pdfFile): pngFile = pdfFile.replace(".pdf", ".png") result = os.popen("cd %s; convert -density 600 -geometry 1000 %s %s"%(DATA, pdfFile, pngFile)).read() # print result return pngFile def printFile(name): fileName = DATA+name file = open(fileName) txt = file.read(); file.close() print txt
Rとのインタフェースとして、r関数が提供されています。 r関数では、Rのコマンドを文字列で与えます。Rのコマンド内でダブルクォートを使っている場合には、シングルクォートでくくり、 Rのコマンド内でシングルクォートを使っている場合には、ダブルクォートを使って指定します。
r('Rのコマンド')
RのコマンドにSageの変数の文字列を代入する場合には、以下のように%を使ってセットします。
r('Rのコマンド1%s, Rのコマンド2%s' % (変数1, 変数2))
上記の例では、1番目の%sが変数1に、2番目の%sが変数2の値に置き換わります。
r関数の例として、Rで計算させた2のsqrtの結果を出力します。Rの出力では最初に[1]のように番号が付いて 表示されます。
sageへの入力:
# Rインターフェース r('sqrt(2)')
sageの出力:
[1] 1.414214
関数定義やRの制御コマンド(ループやif文等)を含む複数行のRコマンドをSageから実行する場合には、 ファイルにまとめてワークシートにアップロードして使います。
例でとしてmystats.txtに以下のように自乗を計算するx2関数を書いておきます。
sageへの入力:
# Rの関数や複数行にわたる制御文は、テキストファイルにまとめて printFile("mystats.txt")
sageの出力:
x2<- function(x) { return (x^x) }
ファイルに定義されたRのコマンドを読み込み評価するには、Rのsourceコマンドを使用します。
以下の例では、mystats.txtに書かれたx2の関数定義を実行し、リストlの各要素に関数x2を適応しています。
sageへの入力:
# Source関数でテキストファイルの内容を評価実行します filename = DATA+"mystats.txt" r('source("%s")' % filename) # リストlの各要素に関数x2を適応する r('l <- c(1, 2, 3)') r('lapply(l, x2)')
sageの出力:
[[1]] [1] 1 [[2]] [1] 4 [[3]] [1] 27
SageとRとの連携で重要なポイントはSageの変数をどうやってRに渡すかです。
以下の例では、変数slに[1, 2, 3]のリストをセットし、これをr関数に渡しています。 このままですとrlに返されるRElementオブジェクトの名前がSagexxのように自動で 割り当てられてしまします。
そこで、name関数でRにおける変数名を指定します。
rl = r(sl).name('l')
説明でRの変数とSageの変数を混同しないようにRでの変数名をlとし、r関数の返した 値をrl変数にセットします。
出力結果から、r('l')で正しくslのリストがRに渡っていることが確認できます。 また、rlのタイプは、sage.interfaces.r.RElementであり、その値の出力結果は r('l')と同じであることも確認できます。
sageへの入力:
# Sageの変数(リスト)をRに渡す sl = [1, 2, 3] # RにSageの変数slを渡し、Rでの変数名をlとする rl = r(sl).name('l') print r('l') print type(rl) print rl
sageの出力:
[1] 1 2 3 <class 'sage.interfaces.r.RElement'> [1] 1 2 3
リストの次にRでよく使われるのがマトリックスです。 例として、r.matrix関数を使って[1, 2, 3, 4]のリストから、2x2のマトリックスを作成します。 byrow=Trueとすることで、Sageと同じ行単位での配置を指定しています。 (RではFORTRANの影響で列単位で配列を保持しています)
sageへの入力:
# マトリックスの生成も同様に生成後に名前をつけて代入すればよい m = r.matrix([1, 2, 3, 4], 2, 2, byrow=True).name('m'); m
sageの出力:
[,1] [,2] [1,] 1 2 [2,] 3 4
Rに定義された変数mの値を出力すると、上記の出力と同じことであることが確認できます。
sageへの入力:
# rでも同じ変数名が定義される r('m')
sageの出力:
[,1] [,2] [1,] 1 2 [2,] 3 4
次にRのマトリックスをSageのマトリックスに変換する方法を示します。
先に定義されたRのマトリックスmをsageobj関数を使ってSageのマトリックスに変換します。 以下の例では、r('m')で返されたRElementをsageobjでSageの変数smに代入し、 その値とタイプを確認しています。smは正しく変換され、smのタイプも sage.matrix.matrix_integer_dense.Matrix_integer_denseとなっていることが 確認できます。
sageへの入力:
# Rのマトリックス変数をsageの変数に変換する print type(m) sm = sageobj(m) show(sm) print type(sm)
Sageの変数smからRのマトリックスに変換する場合には、listメソッドを使ってマトリックスsm をリストに変換し、smの行、sm列を使ってRのマトリックスに変換します。
sageへの入力:
# Sage => Rの場合には、listメソッドでマトリックスからリストに変換する r.matrix(sm.list(), sm.nrows(), sm.ncols(), byrow=True)
sageの出力:
[,1] [,2] [1,] 1 2 [2,] 3 4
残念ながら、Sageの文字列リストは、そのままではRの文字列リストに変換されません。 そこで、文字列リストをstr関数を使って文字列に変換し、最初[と最後の]を取り除いて、 r('c(%s)'%文字列リスト)を使ってRの文字列リストに変換します。
sageへの入力:
# 文字列のリストの場合には、上記の方法では上手くいかない ary = ["a", "b"] ss = str(ary)[1:-1]; print ss # リストを文字列に変換して[、]を取り除く rary = r('c(%s)'%ss).name('rary') print rary # Rに変換した配列 sary = sageobj(rary) print sary # sageに戻した配列
sageの出力:
'a', 'b' [1] "a" "b" ['a', 'b']
Rのプロット関数を使う場合には、preGraphとpostGraphで挟むようにします。
sageへの入力:
# 正規分布をRインターフェースを使って表示 graph = preGraph("fig1.pdf") r('x <- pretty(c(-3,3), 30)') r('y <- dnorm(x)') r('plot(x, y, type = "l", xlab = "Normal Deviate", ylab = "Density", yaxs = "i")') postGraph(graph)
上記と同じことをRの関数dnormの値を使ってSageのplot関数でプロットした例を以下に示します。
sageへの入力:
# 同じグラフをRと連携して表示した例(計算にRの関数を使用) x = var('x') f = lambda x: N(r.dnorm(x)) # r.dnormを使ってRのdnorm関数を呼び出す plot(f, [x, -3, 3], axes_labels=["Normal Deviate", "Density"])
次に、r.plotを使ったプロットの例を示します。X軸にage、Y軸にweightを表示します。 r.plotにX, Yにsageの変数age, weightを使った場合、軸ラベル名にsagexxのような 名前が表示されます。
sageへの入力:
# グラフ表示(軸ラベルが正しく表示されていない) age = [1,3,5,2,11,9,3,9,12,3] weight = [4.4,5.3,7.2,5.2,8.5,7.3,6.0,10.4,10.2,6.1] graph = preGraph("fig2.pdf") r.plot(age, weight) postGraph(graph, fac=0.5)
age, weightにnameコマンドでRの変数名をセットすると、軸ラベルがage, weightと 表示されます。
sageへの入力:
# データのセット age = r([1,3,5,2,11,9,3,9,12,3]).name('age') weight = r([4.4,5.3,7.2,5.2,8.5,7.3,6.0,10.4,10.2,6.1]).name('weight') # グラフ表示 graph = preGraph("fig3.pdf") r.plot(age, weight) postGraph(graph, fac=0.5)
Rのplot関数にタイトル等のオプションを指定する場合には、r関数を使って以下のように表示します。
sageへの入力:
# タイトル等グラフオプションを指定する場合には、r.plotではなくr関数を使用する # 日本語は文字化けする(Windows版では、pdfでは日本語が表示できたが、pngの変換に失敗) graph = preGraph("fig4.pdf") r('par(family="Japan1Ryumin")') r("plot(age, weight, main='Test plot')") postGraph(graph, fac=0.5)
Rの得意とする集計処理を以下のようなデータファイルを読み込み、 クロス集計を作成してみましょう。
sageへの入力:
# データファイル printFile("Data.txt")
sageの出力:
diabetes status Type1 Poor Type2 Improved Type1 Excellent Type1 Poor
データファイルの読み込みは、Rのread.table関数を使用します。 header=Tを付けて、1行目がヘッダであり、 1列目がdiabetes、2行目がstatusと名前付けします。
sageへの入力:
# データファイルの読み込み fileName = DATA + 'Data.txt' d = r("d<-read.table('%s', header=T)" %fileName) ; d
sageの出力:
diabetes status 1 Type1 Poor 2 Type2 Improved 3 Type1 Excellent 4 Type1 Poor
クロス集計には、table関数を使用し、データセットdの変数、 diabetes, statusを指定します。
sageへの入力:
# クロス集計 r('table(d$diabetes, d$status)')
Excellent Improved Poor Type1 1 0 2 Type2 0 1 0
皆様のご意見、ご希望をお待ちしております。