Rのプログラミング


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(条件�) { ... }

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 を使��

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)

多��:switch()

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 のベクトルでなければなりません  

条件式に使われる記号一覧表

関係演算�
< 左辺が右辺より大きい
<= 左辺が右辺以�
> 左辺が右辺より小さ�
>= 左辺が右辺以�
== 左辺が右辺と等し�
!= 左辺が右辺と等しくな�

論理演算�
&, &&
右辺かつ左辺が正しい
|, ||
右辺また�左辺が正しい
! 否�
論理関数
all 要�がすべて真値の場合�み TRUE
any 要�の中に一つでも真値があれ� TRUE

論理演算子�&&」�||」�スカラー量に対して適用され、結果は論理値 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」構文を使�

while(条件�) {
	...
}

repeat, break

ある命令群を無条件で繰り返し実行する�合には�repeat」構文を使��
ループから脱出する場合�、�break」�入った条件�使��

repeat {
	...
	if(...) break
...
}

next, break

ループ�途中である条件を満たしたら残りのループをスキ��して、�びループ�先�から�直す�合には�next」命令を使�ある条件を満たしたらループを脱出する場合には�break」命令を使��

for()

ある値の�のそれぞれのケースにつ�命令を実行する�合には�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(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

 

 

 

もど�