|
R はインタープリタ型なので、�ログラ�を実行させると、毎回�行ずつ機械語に翻訳して実行する�で実行速度は�。そのため、�ログラ�は関数として定義し、あらかじめ機械語に翻訳させておき、�に応じて関数を呼び出して計算させる、と�の� R 流�使�である�
R での関数は、C 言語と同じように�常の意味での関数、すなわち�数学関数のように�ある値を別の値に変換する規則と、一連の計算�「手続き」と�両方の意味で使用されて��
R には、�な計算アルゴリズ�にとって���条件�や繰り返しを実現する構文が用意されて�。これらを�合わせて与えれた問題を解� R の命令���ログラ�と��を作ることを�ログラミングと�。ここでは、�ログラミングの知識を解説する�
関数の名前を決めて fix(関数�)
と入力すると�function() { ... }
� と記�された「Rエ�タ」ウィンドウが開く�で、そこで作業する�Enterキーを押してもRconsole画面には反映されな�完�したらクローズ ボックスをクリ�して Rconsole 画面にもどり�の関数と同じように命令�して使�とができる。思い通りの結果にならな��合� edit(関数�)
として�エ�タを表示させ、そこで修正をする�
関数を�扱��合、個別の関数ごとに�fix()
を使って作業してもよ�、すべての定義関数が一覧できた方が文書管��上からも都合がよい。また�数の定義�けではなく、その使われ方につ�も記録に残しておく方が作業効�上がる。Rエ�タは一関数の定義�けに止まらず�常のエ�タとして使�とができる。RStudio なら�左上にエ�タが表示されて�が、RGui 画面では「ファイル」メニューの「新しいスクリプト」サブメニューを選択すると「Rエ�タ」ウィンドウが表示され、テキストが入力可能になる。そこに�の命令�書き、それを選択して F5キーを押�と、Rconsole 画面に転送され、結果� Rconsole 画面に表示される�
関数定義ではなく、数式�力�場合でも、�力�容が�になった�合�、エ�タで入力すべき数式を整えてから R console に送る、と�作業手���作業効�高めてくれるだろう�
関数を定義する場合��数� = function( ) に続けて関数定義の命令�を書く。function( ) のかっこ�には�に応じて仮引数リストを書くことができる�
定義した関数を呼び出す�合�、「関数�(実引数リス�)」と書く。引数がな��合でも�( )」を書かなければ�な��
�( )」を書かな�関数名だけ�力して Enter キーを押すと�数の定義が表示される�
関数� = function(引数リス�) { 関数定義命令群 }
関数定義の引数リスト�、変数名を�,」で区�て並べる�
変数名だけではなく、代入�右辺は定数�とすると、その右辺値がデフォルト値として与えられる�
関数を呼び出す�合、デフォルト設定をして��数は�実引数を書かなければ�な��
ある条件を満たした�合だけある命令群を実行したい場合には�if
」構文を使��
ある条件を満たした�合�ある命令群を実行し、満たさなかった�合�別の命令群を実行したいと�場合には�if ... else ...
」構文を使��
if(条件�) { ... } if(条件�) { ... } else { ... }
たとえ���
if(n == 1) stdev = 0 else stdev = sd(x)
else
以下�命令群がまた条件��if ��場合��else if
」と書く�
�行にわたっても良��else
の前で改行すると if
構文とみなされ�else
は新たな命令とされるが�else
で始まる命令はな��で�違反になる。else の前�実行文� { } で囲み、最後� } の前で改行し、ま�入力が終わって��とを�示�知らせる�がある。あるいは、�体を { } で囲むと } が読み込まれるまでを�とかたまり�命令とみなされる�で、else が行�にあっても文法違反にならな��
> a = 1 > if(a == 0) print("zero") > else print("non-zero") エラー: 予想外� 'else' で� in "else"
# else の前に } が来るよ�する
> if(a == 0) { print("zero") + } else print("non-zero") [1] "non-zero"
# ある��、�体を { } で囲む
> { + if(a == 0) print("zero") + else print("non-zero") + } [1] "non-zero"
数学関数のように、スカラーの独立変数をある値に変換する関数で、独立変数に関して条件�によって値を決める場合には注意が�である。このような関数の場合、�クトルを独立変数にしたときに、要�ごとに関数値を計算して、結果を�クトルとして返すようにしておかな�、ある種の計算で不�合が生じる�
例えば、max(x, 0) を関数として定義する場合を例にとると�
maxplus = function(x) if(x > 0) x else 0
と書け�よさそうなも��が、引数にベクトルを指定すると正しい計算が実行されな�なぜなら� if で判定した結果は一つの論理値しかかえすことができな��で、この場合�ベクトルの先�の要�が正である時に TRUE さもなければ FALSE とする�になって�。そ�らな�めに、�クトル化した条件��関数 ifelse を使��
長� n の論理ベクトル A と長� n の�つのベクトル u, v に対して ifelse(A, u, v) は、A[i]=TRUE なら� u[i]、さもなければ v[i] (i=1,...,n) を返す関数である。従って、�に挙げた関数 max(x,0) � ifelse 関数を使って書�おけば、引数が�クトルであっても対処できる�
> maxplus = function(x) if(x > 0) x else 0 > maxplus(-1) # スカラーなら�結果は正しい [1] 0 > maxplus(-1:1) # ベクトルには対応できな� [1] 0 警告メ�ージ: In if (x > 0) x else 0 : 条件が長さが 2 以上なので、最初� 1 つ�けが使われま� > curve(maxplus, -2, 2) # グラフが描けな� 以下にエラー curve(maxplus, -2, 2) : 'expr' は長� 'n' のオブジェクトを評価しませんでした 追���: 警告メ�ージ: In if (x > 0) x else 0 : 条件が長さが 2 以上なので、最初� 1 つ�けが使われま�
> maxplus = function(x) ifelse(x > 0, x, 0) # 正しい関数定義 > curve(maxplus, -2, 2)
�else if
」が繰り返される場合��switch
」構文で置き換えた方が見やすくなる�合がある�
「which(条件式��)」関数は、条件式を満たす要�番号を返すので、これと�合わせることで�な計算を簡略化することができる。たとえ�、x � 0 以� 1 以下�時� 2x�1 以� 2 以下�時� 2(2 - x)、それ以外�時� 0、と�三角形の形をした関数を定義するには次のようにすればよい�
> x = 0.5 > switch(which(c(x<0, 0<=x && x<1, 1<=x && x<2, x>= 2)), 0, 2*x, 2*(2-x), 0) [1] 1 > switch(which(c(x<0, x<1, x<2, x>= 2)), 0, 2*x, 2*(2-x), 0) 以下にエラー switch(which(c(x < 0, x < 1, x < 2, x >= 2)), 0, 2 * x, 2 * (2 - : EXPR は長� 1 のベクトルでなければなりません
|
|
|
論理演算子�&&
」�||
」�スカラー量に対して適用され、結果は論理値 TRUE ある�� FALSE になる。�&
」�|
」�ベクトルの��ごとに適用され、結果は論理値ベクトルになる。�!
」�スカラーでも�クトルでもよく、�クトルの場合���ごとに適用され、結果は論理値ベクトルになる。また、�!
」��&
」�|
」に優先する�
all は�&
」を多��算に拡張したも�で、引数の論理値ベクトルの要�すべて� TRUE の場合にのみ TRUE となる。結果は論理値である�
any は�|
」を多��算に拡張したも�で、引数の論理値ベクトルの要�すべて� FAULE と�場合以外に TRUE となる。結果は論理値である�
条件式が正しい場合� TRUE と�論理定数が返される。さもなければ FALSE が返される。論理型変数に論理値を代入する時、TRUE, FALSE の省略形で T, F も許されるが、T, F は一般の変数として使われ���で注意が�である。T, F に値が代入されると�常の変数と同じ扱�なる�
論理式に数が現れると、ゼロ� FALSE、ゼロ以外を TRUE に置き換えてから計算される�
> x = c(0,0,1,1); y = c(0,1,0,1) > !x [1] TRUE TRUE FALSE FALSE > x & y [1] FALSE FALSE FALSE TRUE > x | y [1] FALSE TRUE TRUE TRUE > ! x & y # ! は & に優先す� [1] FALSE TRUE FALSE FALSE > ! (x & y) [1] TRUE TRUE TRUE FALSE
> x && y # x[1] && y[1] と同じ [1] FALSE
> any(x) # ゼロ以外�数が混ざって�ので TRUE [1] TRUE 警告メ�ージ: In any(x) : 'double' 型�引数を論理型に変換しま�
ある条件を満たして�場合だけ指定された計算を実行する�合には�while
」構文を使�
while(条件�) { ... }
ある命令群を無条件で繰り返し実行する�合には�repeat
」構文を使��
ループから脱出する場合�、�break
」�入った条件�使��
repeat { ... if(...) break
...
}
ループ�途中である条件を満たしたら残りのループをスキ��して、�びループ�先�から�直す�合には�next
」命令を使�ある条件を満たしたらループを脱出する場合には�break
」命令を使��
ある値の�のそれぞれのケースにつ�命令を実行する�合には�for
」構文を使��
while
構文、あるいは repeat + break
構文を使っても表現可能であるが、�ログラ�のわかりやすさ�デバッグの手間�を�ると、標準的な for
構文で書ける場合�、なるべくそ�たほ�良��
for(i in ...) { ... }
�つか��
> for(k in 1:3) print(k) [1] 1 [1] 2 [1] 3 > n = 0; for(k in 1:n) print(k) [1] 1 [1] 0 > x = 1:7; for(a in which(x%%3 == 0)) print(a) [1] 3 [1] 6 > for(a in c("A", "B", "AB", "O")) print(a) [1] "A" [1] "B" [1] "AB" [1] "O"
for(i=1; i<=3; i++) { ... }
となる)�for(i=1; i<=n; i++)
の n=0 の場合と同じではな��for(a in A)
の A は、その後に続く { ... }
の処�は無関係である。また、a は { ... } が終わると、最初に与えられ� A の次の要�に設定し直される。したがって�{ ... }
の中で a � A の値を変更しても、繰り返し回数には影響が無��
> A = 1:3 > for(a in A) { + print(a) + a = a*10; print(a) + A = c(A, a); print(A) + } [1] 1 [1] 10 [1] 1 2 3 10 [1] 2 [1] 20 [1] 1 2 3 10 20 [1] 3 [1] 30 [1] 1 2 3 10 20 30
変数は定義しな�使って良��数の�で値が代入される変数は�数が終�ると同時に消去され、その値は保存されな�このような変数はローカル変数と呼ばれる�
関数の外�で使用して�変数を実引数としな��数�で使���合、参照する�けなら�特別な注意��な�値を変更した��合�、代入演算子として�<-
」あるいは�=
」ではなくて�<<-」(永続代入演算子と��としなければ�な�。このような変数はグローバル変数と呼ばれる�
> a = 10 > test = function() { + a = 100 # これはローカル変数 a への代入 + print(a) + } > test() [1] 100 > a # 関数定義の代入��反映されな� [1] 10 > test = function() { + a <<- 100 # これはグローバル変数 a への代入 + print(a) + } > test() [1] 100 > a [1] 100
関数で計算した値を返すには�return()
」命令�使��
返す値が�ある場合�、c 関数を使ってベクトルで返す。names() 関数を使って名前を付けておくと、どのような計算をしたのかわかり���
返す�のも�が異なるデータ型�場合��list
関数を使�
########################## 名前を付けて返す
> stats = function(x) { + res = c(mean(x), sd(x), max(x)-min(x)); + names(res) = c("平�", "標準偏差", "�") + return(res) + } > > stats(c(1,2,3,4)) 平� 標準偏差 � 2.500000 1.290994 3.000000
########################## list 関数で返す
> statss = function(x) { + return(list(mean = mean(x), sd = sd(x), order = sort(x))) + } > statss(c(3,4,1,2)) $mean [1] 2.5 $sd [1] 1.290994 $order [1] 1 2 3 4
関数の実行中に、キーボ�ドからデータを�力させた��合��readline()
関数を使��力された行を��として受け取るので�strsplit(z, "[ ,]")
関数で��に�する�"[ ,]"
は正規表現で、データはスペ�ス区�でもカンマ区�でもよ�して�。文字�は list
構�になって�ので�unlist
関数でベクトル化し、数値に置き換える��as.numeric
関数�と�作業が�になる�
# 入力データの平�標準偏差を計算す� > test = function() { + z = readline() + w = as.numeric(unlist(strsplit(z, "[ ,]"))) + return(c(mean(w), sd(w))) + } > test() 1 2 3 [1] 2 1
関数定義の中で、結果を表示させる�合� print
関数を使��ある場合� c 関数でベクトルとしてから表示させる、あるいは��を表示する cat
関数を使�変数は自動的に��に変換されて、文字�が書かれた��に表示される。改行したい場合�、文字��"\n"
」を使��
printf
関数を使っても良�これ�、C言語� printf()
とほとんど同じで、結果を書式にしたがって変換した��を返す関数である�
> y = 11; cat("y=", y, "\n") y= 11
fix(関数�) を実行して関数を定義した場合�、save ボタンをクリ�すれば良�通常のエ�タ画面で作業して�場合�、拡張子�.R
」を付けて保存する。とする。この場合�一つの関数�けを hello.R
の名前で保存して�が、定義関数は�つあってもかまわな��
test = function() { cat("Hello R world!¥n") } save(test, file="hello.R")
source(hello.R) # �ォルト��レクトリを使��� # R console 「ファイル」メニューの「ディレクトリの変更」を使って保存したファイルを指定す� # 関数の実� > test() Hello R world! # 定義関数の除去 rm(test) # 定義�の確� > test