DATE : 2008/04/05 (Sat)
R の関数を書くときには、使い方などのコメントを関数の内側に書くと便利です。
R で関数オブジェクトを呼び出すと、その関数のソースコードが表示されます。例えば、次のような関数があったとします。
# 引数同士を足し合わせる。 # # 引数: # a : 足される数 # b : 足す数 # 戻り値: # a と b を足し合わせた数 add <- function(a, b) { # 計算結果を返す return(a + b) }
この関数オブジェクトを次のように呼び出すと、次のように関数のソースコードが表示されます。(「>」はプロンプトです)
> add function(a, b) { # 計算結果を返す return(a + b) }
ここで、関数の使い方を記した関数外部のコメントは消えていますが、内部のコメントは残っていることに気づきます。
そこで、関数の使い方を関数内部に入れてしまいます。
add <- function(a, b) { # 引数同士を足し合わせる。 # # 引数: # a : 足される数 # b : 足す数 # 戻り値: # a と b を足し合わせた数 # 計算結果を返す return(a + b) }
このようにすると、関数オブジェクトを呼び出したときに関数の使い方も分かって便利です。
> add function(a, b) { # 引数同士を足し合わせる。 # # 引数: # a : 足される数 # b : 足す数 # 戻り値: # a と b を足し合わせた数 # 計算結果を返す return(a + b) }
(;^ω^)これまでは、Java などの癖で関数定義の上に書いていました。ところがある日、関数内部のコメントが残っていることに気づき、R の関数のコメントは関数内部に書くようにしました。
DATE : 2008/03/14 (Fri)
データフレームから条件式が成り立つ行のみを抽出する subset という関数があります。例えば、result データフレームの「x」という列の値が0を超える行のみを抽出するには、次のようなコードを実行します。(「>」や「+」はプロンプトです)
> subset(result, 0 < x)
通常、データフレームの列にアクセスするには、「result$x」とするか、「result['x']」としなければなりません。ただ単に x と書いても、x という名前のオブジェクトが参照されるだけです。ところが、subset 関数の場合は、条件式に当たる部分では自動的にデータフレームのオブジェクトを補ってくれます。そのため、subset 関数の条件式の部分では、ただ単に列名のみを書くだけで十分です。
このような subset 関数を R で直接実行する分には、なんの問題もありません。ところが、あるとき subset を内部で使う関数を書いていたときに、はたと困ってしまいました。条件式の渡し方が分からなかったのです。例えば、次のような関数を実行しようとしても、失敗してしまいます。
> subset_function <- function(condition) { + subset(result, condition) + } > subset_function(0 < x) 以下にエラー eval(expr, envir, enclos) : オブジェクト "x" は存在しません
R では、式は必要になるまで評価されません。そのため、subset_function に渡した条件式は評価されずに関数内部に入ります(遅延評価)。ところが、関数内部の subset の部分で評価が失敗しているようです。
しばらく悩んだところ、次のような解決策が思い浮かびました。
> subset_function <- function(condition) { + subset(result, eval(condition)) + } > subset_function(expression(0 < x))
式表現を渡して、subset のところで評価するという方法です。ところが、いまひとつスマートではありません。実際、subset 関数は expression 関数を使用せずに式を評価できています。
そこで、R 2.6.2 のソースコードから、subset 関数を定義している部分(src/library/base/R/frametools.R)を調べてみました。条件式の評価に関わる部分のみを抜き出すと、次のようになります。「(...)」は省略を表します。
subset.data.frame <- function (x, subset, select, drop = FALSE, ...) { (...) e <- substitute(subset) r <- eval(e, x, parent.frame()) (...) }
subset 関数の定義を診ると、条件式(subset)は、substitute 関数に渡され、その結果が eval 関数に渡されています。まず、substitute 関数によって式を解析木オブジェクトに変換しています。そして、eval 関数によって、その解析木を渡されたデータフレームの環境で、そのデータフレームは親の呼び出しスタックから取得するという処理になっています。eval の引数は少々分かりづらかったのですが、引数として渡されたデータフレームに対して評価を行う際の書き方であると、eval 関数のヘルプに書かれていました。subset_function は、引数でデータフレームを受け取ってはいませんが、親の呼び出しスタックにあるデータフレームを関数内で直接使っています。そのため、データフレームの取得に親の呼び出しスタックを使用しています。
subset 関数の定義が上のようになっていたので、subset_function も次のように書き直せます。
> subset_function <- function(condition) { + e <- substitute(condition) + r <- eval(e, result, parent.frame()) + subset(result, r) + } > subset_function(0 < x)
このようにすることで、条件式をそのまま使用できるようになりました。
注意
上の関数の内容を、以下のように1行にまとめた場合はうまく動作しません。
> subset_function <- function(condition) { + subset(result, eval(substitute(condition), result, parent.frame())) + }
subset 関数の引数となる eval 関数や、その引数となる substitute 関数は、遅延評価のために、その関数の実行される呼び出しスタックが、subset 関数以下になります。そのため、result のある呼び出しスタックがうまく呼び出せずに失敗するようです。
DATE : 2008/02/17 (Sun)
久々に統計処理を行うことになったので、R 2.6.2 を Windows Vista にインストールしました。
Windows Vista にはメイリオが標準で搭載されているので、R GUI を開くともちろんメイリオでコンソールが表示されます。Clear Type で表示されるので、前に BDF M+ を使っていたときよりも表示が滑らかで綺麗です。
ところが、その画面でコマンドを打ち込もうとすると、カーソルの位置と文字の入力される位置とがどんどんずれていくことが分かりました。例えば、カーソルをアンダーバー(_)で表すと、正常であれば、
> read.csv("test.csv")_
となるはずが、
> read.csv("test.csv") _
という具合にずれてしまうのです。
そこで、ほかのフォントに変更しようと思ったのですが、変更がまったく反映されません。R の GUI 設定は、「<r のインストールフォルダ>\etc\rconsole」で管理されており、この設定ファイルを手動、もしくは R の GUI 設定ウィンドウから保存で変更すれば、次回の起動時にもフォントの変更が反映された状態になります。
はじめは、Vista 特有の問題かと思いました。R 公式の R Windows FAQ の2.24にも、Vista では管理者権限がないと動作がおかしくなる場合があると記されていました。しかし、いろいろ試してみましたが、やっぱりうまくいきません。
そこで、R の動作のうち、設定ファイルに関係していて怪しい部分を調査してみることにしました。R の GUI 設定ウィンドウで Rconsole ファイルの読み込み・保存をする際にまず開くフォルダは、なぜか使用中のユーザのドキュメントフォルダでした。R を起動したショートカットから、R の作業フォルダの設定を見てみます。すると、作業ディレクトリがユーザのドキュメントフォルダになっていました。しかし、作業ディレクトリの変更を行っても、フォントはメイリオのままです。
そこで、ふと以前に R を使っていた頃を思い出しました。そのころ使っていた R では、GUI 設定ウィンドウから設定を保存しようとすると、「<R のインストールフォルダ>\etc」がまず開かれていました。「もしかして、その場所に Rconsole ファイルを置けば反映されるかもしれない」と考え、さっそくそこに、フォント設定を変えた Rconsole ファイルを置いてみました。すると……。
「この場所には同じ名前のファイルが既にあります。」
( ゚д゚)……
(゚д゚ )……
なぜか、Rconsole ファイルが既にありました。おそらく、GUI 設定ウィンドウをいじっているうちに、いつの間にかドキュメントフォルダに保存してしまったのでしょう。ドキュメントフォルダの Rconsole ファイルを消してみます。すると、きちんと「<R のインストールフォルダ>\etc\Rconsole」にある Rconsole ファイルが適用されて、コンソールのフォントが変わりました orz
(;´Д`)実に情けないミスでした。これで1~2時間は潰れたような気がします
DATE : 2007/06/18 (Mon)
リストやデータフレームからベクトルを取り出すには、[[ ]] か $ でインデックスを指定します。
例えば、R 内蔵のデータセット iris から花びらの長さ(Petal.Length)をベクトルとして取り出すには、次のようにします。(「>」はプロンプトです)
> iris[[ "Petal.Length" ]] > iris$Petal.Length
[ ] でインデックスを指定してもリストから要素を取り出すことはできます。ただし、この場合はベクトルとしてではなく、リストとして取り出されます。リストの一部をそのまま取り出すという具合です。
なお、 [[ ]] と $ とでは細かいところで動作が異なります。[[ ]] の場合は、 [[ ]] 内が式として評価されますが、 $ では評価されません。
リストからベクトルを取り出すか、リストを取り出すかという違いは、関数を使用する際に重要となってきます。関数の中には、ベクトルしか受け付けないものもあります。そのような関数にリストを渡してしまった場合、次のようなエラーが出ます。
> pairwise.t.test( iris[ "Petal.Length" ], iris[ "Species" ] ) 以下にエラーsort.list(unique.default(x), na.last = TRUE) : 'x' は 'sort.list' に対してはアトミックでなければなりません。 'sort' をリストに対して呼び出しましたか?
この例の関数の場合、次のようにベクトルとして値を渡すときちんと動作します。
> pairwise.t.test( iris[[ "Petal.Length" ]], iris[[ "Species" ]] )
参考文献
DATE : 2007/05/08 (Tue)
棒の先端に項目名のある横棒グラフは、次の手順で描くことができます。
- 項目名のない横棒グラフを描く。
- 項目名を各棒の先端に描く。
例を描く際に使用するのは、1ユーロに対するユーロ圏各国通貨の換算レートです。このデータセットは R に内蔵されているので、以下を実行すると換算レートを表すベクトルが出てきます(「>」はプロンプトです)。help 関数で詳細を調べることもできます。
> euro
結果の一部を取り出すと、次のようになっています。
ATS BEF DEM ESP FIM FRF 13.760300 40.339900 1.955830 166.386000 5.945730 6.559570
ベクトルの各要素にはユーロ圏各国通貨の名前が付けられています。例えば、ATS はオーストリア・シリングです。
なお、R 2.5.0 Windows 版で動作を確認しています。
項目名のない横棒グラフを描く
項目名のない横棒グラフは次のように描きます。
> names.y <- barplot(euro, horiz = TRUE, names.arg = NA)
横棒グラフを描くには horiz = TRUE に設定します。項目名を表す names.arg 引数は、項目名を描かないように NA と設定します。なお、horiz = TRUE と設定すると下から順に棒グラフが描かれます。上から順に描くには、rev 関数を使って euro のベクトルを逆順にします。
ここで、 barplot 関数の戻り値を names.y に代入しています。barplot は、各棒の先端の中心座標(横棒グラフの場合は y 座標)をベクトルとして返します。
項目名を各棒の先端に描く
各棒の先端の中心座標を使って、項目名を描きます。
> text(euro, names.y, names(euro), pos = 4)
x 座標に棒グラフの長さ(=換算レート)を指定し、y 座標に各棒の先端の中心座標 names.y を指定します。euro のベクトルから names 関数を使って項目名を取り出します。文字列の配置を表す引数 pos は 4(座標の右側)に設定します。横棒グラフで項目を上から描いた場合は、ここでも euro のベクトルを逆順にします。
なお、上で描いたグラフは ITL(イタリア・リラ)の換算レートのきりが悪いため、この項目名だけ表示されません。そのような場合、以下のようにグラフの x 軸の範囲を調節します。
> names.y <- barplot(euro, horiz = TRUE, names.arg = NA, xlim=c(0, 2500)) > text(euro, names.y, names(euro), pos = 4)
x 軸の範囲を調節すると、きりが悪いために表示されない項目名も表示できるようになります。この例では、0 ~ 2500 に設定しました。