Rの関数定義の基本
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
検索
|
最終更新
|
ヘルプ
]
開始行:
#contents
//間瀬茂
*本項目について [#t2db350f]
R での処理は一連の関数を用いて行なわれます。
既に多くの関数が定義されており、それだけでも一通りの解析...
R には、最初から関数を簡便に定義するための多くの便利な機...
いずれにしても、一旦定義されれば、自前の関数も、R 固有の...
//(ほぼ完成かな。後は自由に修正、追加お願いします。
//間瀬 (2003/6/28)
*関数定義の基本書式 [#j5769b89]
> foo <- function(引数リスト) 関数本体 # 関数本体が一...
> foo <- function(引数リスト) {関数本体} # 関数本体が複...
> "foo" <- function(引数リスト) 関数本体 # この形式もあ...
警告:COLOR(red){R の組み込み関数は自由に再定義可能}であ...
*本体 [#d0f74300]
関数本体は R の式を必要なだけ並べたものです。一つの行に複...
# 例
> foo <- function(x, y) { # foo という名前の関数を二つ...
z <- x + y; w <- x * y # セミコロンで区...
if (z > w) t <- z # 好みで if (...
else {t <- w; w <- z; z <-t} # 波括弧で...
for (i in 1:10) { w <- w + i; z <- z - i}
cat("z = ", z, " w = ", w, "?n")
return (list(w, z)) # 二つの返り値
}
> foo(2, 3) # すぐ実行できる
*引数 [#if5c32ea]
**引数リスト [#w1f86bdf]
-引数リストはコンマで区切った(仮)引数名のリスト
> foo <- function () cat("R is fantastic! ?n") # 引数なし
> foo1 <- function (x) x^2 # 引数一つ(自乗値を計算)
> foo2 <- function (x,y) x*y # 引数二つ(積を計算)
> foo3 <- function (x,y,z) { # 引数3つ(本体が長いので括...
w <- exp(x)*(y+z)
cat("x=",x,"y=",y,"z=",z, "result=",w)
}
**名前・既定値つきの引数 (2004.8.13) [#lbada251]
-COLOR(red){引数名=既定値} の形式で既定値を指定できる(関...
> foo <- function(x=1, y=2) x+y # 既定値つき(名前つ...
> foo() # 既定値 x=1, y=2 と解釈
[1] 3
> foo(0.1, 20) # x=0.1, y=20 と解釈
[1] 20.1
> foo(x=0) # 既定値 y=2 が使われる
[1] 2
> foo(y=0) # 既定値 x=2 が使われる
[1] 1
> foo(x=5, y=6)
[1] 11
> foo(6) # 既定値 y=2 が使われる
[1] 8
> foo(6,) # 上と同じ
[1] 8
> foo(,6) # 既定値 x=1 が使われる
[1] 7
次のような(場合により値が異なる)既定値つきの引数を与える...
> test <- function (x, y=ifelse(x>=0, 1, -1)) {cat(x,y,"...
> test(1, 2) # y 引数を与えればそれが第二引数の値になる
1 2
> test(1) # y 引数を省略すると、x 引数に応じた既定値が第...
1 1
> test(-1)
-1 -1
digitsBase(x, base = 2, ndigits = 1 + floor(log(max(x), ...
という関数は次の様にさまざまな引数の与え方で実行できる
(1) digitsBase(10) base と ndigits は既定値が使われる
(2) digitsBase(10, base = 8) base と ndigits は既定値が...
(3) digitsBase(10, ndigits = 5) base に既定値 2 が使われる
(4) digitsBase(10, base = 8, ndigits = 5) 既定値なし
-名前つき引数指定 option = value では、引数名 option は一...
関数 foo <- function (x, mab = 3, mbc = 0.1, bar = 10) {...
foo(3)
foo(3, ma=4, mb=1)
foo(3, b=4)
-関数の実際の呼出しにおいて、複数の引数は名前付きで与える...
-COLOR(red){注意}:名前つきでない引数も実際は暗黙の内にCO...
> test <- function(x,y) print(x+y)
> test(1,2)
[1] 3
> test(x=1,2)
[1] 3
> test(1,y=2)
[1] 3
> test(x=1,y=2)
[1] 3
> test(y=2, x=1)
[1] 3
**引数として関数オブジェクトを与える場合 (2004/09/15) [#n...
引数として関数オブジェクトを与えることができる。
普通関数オブジェクト名を引数として与える:
test <- function(x, fun=sin) {plot(x, fun(x))}
test(1:100/100) # 既定の関数 sin ...
test(x, fun=cos) # 関数として cos ...
test(x, fun=function(z) 1/(1+exp(z))) # 関数定義を直接与...
関数自身がオプション引数をもち、それを特定の値に指定した...
util <- function(x , opta=1, optb=0) # オプ...
test(1:100/100, fun=test(x, opta=10, optb=-1) ) # エラ...
my.util <- function(x) util(x, opta=10, optb=-1) # オプ...
test(1:100/100, fun=my.util) # 正し...
# もしくは引数として関数定義を直接書いても良い
test(1:100/100, fun=function(x) util(x, opta=10, optb=-1))
**特別な(その他大勢)引数 ... (2004.8.13) [#pdfd1871]
-特別な引数として COLOR(red){...} が使える.これは任意の...
> foo <- function(x, ...) {
if (x >= 0) return(x*cos(...[1]) + x^2*sin(...
else return(exp(x))}
> foo(1,c(2,3)) # ... にベクトル値
[1] -0.2750268
> foo(-1) # ... 部分の引数無し。実際この場合...
[1] 0.3678794
-特殊引数 COLOR(red){...} は関数引数欄の最後におかれるの...
この特徴は面倒のようにも思えるが、COLOR(red){...} 引数は...
> test1 <- function(x, y=3, ...) (x+...[1])^y
> test2 <- function(x, ..., y=3) (x+...[1])^y # ... 引...
> test1(1); test2(1)
[1] 8 # = (1+1)^3
[1] 8 # = (1+1)^3 # ...[1] = 1 とされている (?)
> test1(1,2); test2(1,2)
[1] 4 # (1+1)^2
[1] 27 # (1+2)^3 # ...[1] = 2 とされている (問...
> test1(1,2,3)
[1] 16 # (1+3)^3
> test2(1,2,3) # ... 引数の後の引数は名前付き...
Error in ...[1] : incorrect number of dimensions
> test2(1,2,y=3)
[1] 27 # (1+2)^3 # y 引数を名前付きで与えた (問...
参考: ... 引数は関数引数欄に明示的に与えなくても不思議...
> test3 <- function(x, y=3, ...) print(...[1])
> test3(1)
[1] 1 # ...[1] = 1 とされている
> test3(3,2)
[1] 1 # ...[1] = 1 とされている
> test3(3,2,1)
[1] 1 # ...[1] = 1 とされている
> test4 <- function(x, y=3, ...) print(c(...[1],...[2],....
> test4(3)
[1] 1 2 3 # ... = c(1,2,3) とされている
その他大勢引数が実際は複数の引数になるとき、k 番目の項目...
> test <- function(i,...) print(list(...)[[i]])
> test(1,1,"abc",list(1:4),matrix(1:4,2,2))
[1] 1
> test(2,1,"abc",list(1:4),matrix(1:4,2,2))
[1] "abc"
> test(3,1,"abc",list(1:4),matrix(1:4,2,2))
[[1]]
[1] 1 2 3 4
> test(4,1,"abc",list(1:4),matrix(1:4,2,2))
[,1] [,2]
[1,] 1 3
[2,] 2 4
従って ... 引数が実際は幾つの引数かを知るには length(list...
*返り値 [#x4f3db54]
関数は返り値を持っても良いし、持たなくてもよい。返り値の...
**暗黙の返り値 [#w6ff162e]
もし COLOR(red){return()}, COLOR(red){invisible()} 関数に...
> foo1 <- function (x) x^2 # x^2 の値が暗黙の返り値
**返り値関数 return() [#sd01cac7]
-関数本体に COLOR(red){return()} を置くとその中身が返り値...
-COLOR(red){return()} が複数あっても良いが,いずれかの CO...
> foo <- function (x,y) {return(x+y)}
> foo(1,2)
[1] 3 # x+y が返り値
> foo <- function (x, y) {return(x); cat("sum =", x+y)}
> foo(1,2) # cat は実行されない
[1] 1
> foo <- function (x,y) {if (x>=y) return(x) else return...
> foo(1,2)
[1] 2
> foo(2,1)
[1] 2
**複数の返り値 return() [#mea7984c]
-COLOR(red){return()} 関数の中に,複数の値を置くと,返り...
-リスト成分には名前ラベルを与えることができる
- COLOR(red){この機能は将来廃止されるらしく、R.1.8 からは...
-上の記述はミスリード。return(c(x, y, x+y)) のように、ベ...
> foo <- function (x,y) {return(x,y,x+y)}
> res <- foo(1,2)
> res[[1]]
[1] 1
> res[[2]]
[1] 2
> res[[3]]
[1] 3
> foo <- function (x,y) {return(x=x,y=y,sum=x+y)} # ラ...
> res <- foo(1,2)
> res$x # res[[1]], res[["x"]] でも良い
[1] 1
> res$y # res[[2]], res[["y"]] でも良い
[1] 2
> res$sum # res[[3]], res[["sum"]] でも良い
[1] 3
**コンソールに表示されない返り値 invisible() [#g4f10798]
例えば、非常に大量で、可読性の低い値を返す関数を考えると...
> foo <- functionn (x) return(x)
> foo(1)
[1] 1
> foo <- functionn (x) invisible(x)
> foo(1) # 何も表示されない
> x <- foo(1)
> x # 結果は変数 x に付値されている
[1] 1
COLOR(red){注意}:invisible() 関数は関数の返り値の指定に...
> test <- function(x) {print(x); x <- x+1; x}
> test(3)
[1] 3 # print(x) による出力
[1] 4 # 関数 test の返り値
> temp <- invisible(test(3))
[1] 3
> temp
[1] 4
**途中結果を返す (2004.8.13) [#i0fcbb7d]
普通最後の結果だけが返り値になるという特徴は、途中結果を...
解決策は必要な途中結果を print(), cat() 関数でコンソール...
# 途中結果を print() 関数でコンソールに出力する
> test <- function(x) {for (i in 1:3) print(x+i)}
> test(3)
[1] 4
[1] 5
[1] 6
> temp <- test(3)
[1] 4
[1] 5
[1] 6
> temp # しかし返り値は依然として最後のものだけ
[1] 6
途中結果をベクトルに貯めておき、最後に返り値とするやりかた
> test2 <- function(x) {res <- numeric(0); for (i in 1:3...
> test2(3)
> test2 <- function(x) {res <- numeric(0); for (i in 1:3...
> test2(3)
[1] 4 5 6 # 途中結果のベクトル返り値
結果として返す値の個数(ベクトルの要素数)がわかっている...
> test9 <- function(n) {res <- numeric(n); for(i in 1:n)...
> test9(10)
**永続付値演算子で間接的に返り値を返す(健康のために使い過...
関数中で永続付値演算子を使うと、関数終了後も残る値を変数...
> v <- 1
> test <- function () {v <- 2; v <<- 3; cat("v=", v, "\n...
> test()
v= 2
> v # いつのまにか値が変わっている
[1] 3
この例では関数内部での変数 COLOR(red){v} と永続付値で生成...
もう少し微妙な例:
> test <- function () {v <- 1:3; v[2] <<- 0; cat("v=", v...
> test()
v= 1 2 3 # 局所的な v の値
> v
[1] 1 0 3 # 大局的な変数 v がつくり出され、いつの間にか...
大局的変数への永続付値の便利な使い方は、他の関数で使うべ...
> foo <- function (x, y, z) {.w <<- list(x, y, z)} ...
> foo2 <- function () {.w[[1]] + .w[[2]] + .w[[3]]} # ...
> foo(1, 2, 3) # これで大局的変数 .w (=list(1 , 2, 3)...
> foo2()
[1] 6
COLOR(magenta){教訓: 関数中の永続付値は便利だが使用には注...
** 特定の環境に値を返す (2004.09.30) [#h9d79ab0]
R のすべての実行式は対応する環境を持つ。普通重要になる環...
# 関数の実行環境の親環境(その関数を呼び出した環境)に登録
# mat <<- mat と同じことになる
assign("mat", mat, parent.frame())
assign("mat", mat, .GlobalEnv) # 大局的環境に登録
*エラー処理 [#v56a9451]
**stop() 関数 [#f2de2144]
COLOR(red){stop()} 関数は、現在の式の実行を中断し、その引...
# x が負またはゼロなら中断、正なら log(x) を返す関数
> foo <- function(x) ifelse( x<=0, stop(message="non-pos...
> foo(3)
[1] 1.098612
> foo(-3)
Error in rep(yes, length = length(ans)) : non-positive a...
**warning() 関数 [#o9dcb1ff]
警告メッセージを生成する。 実際の結果は options("warn") ...
-warn が負なら警告は無視される
-warn が零ならば一旦保存され、最上位の関数が終了した際に...
-warn が 1 ならば警告が生起するとすぐに出力され、 2 (もし...
> foo <- function(x) {
if (x<=0) {return(NA); warning(message="NA pr...
else return(log(x)
}
> foo(3)
[1] 1.098612
> foo(-3)
Error in rep(yes, length = length(ans)) : non-positive a...
-結果は COLOR(red){options("warn")} の値に依存する
-もし warn が負なら警告は無視される
-もしそれが零ならば一旦保存され 最上位の関数が終了した際...
-もしそれが 1 ならば警告が生起するとすぐに出力される
-2(もしくはそれ以上)ならば警告はエラーとして処理される。
**stopifnot() 関数(2004/08/14) [#z7955236]
引数としてカンマで区切って並べられた条件が満たされないと...
(stopif という関数仕様の方が素直で便利だと思うのだが)
> a <-3
> b <- 4
:
> stopifnot(a == 3, b==5)
Error: b == 5 is not TRUE
*関数のデバッグ [#x2e0a733]
デバッグは困難な問題であるが、最大の困難ではない。デバッ...
**万能デバッグ関数 cat() [#fe61b76f]
最も安易な関数のデバッグ法は、関数中に COLOR(red){cat()} ...
> foo <- function (x) {
cat("arg x=", x, "?n")
log(x) }
> foo(-1)
arg x= -1 # デバッグメッセージ (なるほど log 関数は...
[1] NaN
Warning message:
NaNs produced in: log(x)
デバッグ用に COLOR(red){cat()} を沢山埋め込んだ後は、すぐ...
> foo <- function (x) {
#cat("arg x=", x, "?n") # 一行コメント...
log(x) }
> foo <- function (x, y) {
if (0) { cat("1st arg =", x, "?n")
cat("2nd arg =", y, "?n") } # 二...
log(x)*log(y) }
注意:if (0) { と } の中には,R の文法上正しいものしか書...
> bar <- function(x) {
+ if (0) {
+ この行はエラーにならないけど,次の行はエラーになる(...
> x <- b±root(b2-4ac)
> }
エラー: 予想外の '}' です ( " }" の)
> return(x+1)
エラー: オブジェクト 'x' がありません
> }
エラー: 予想外の '}' です ( "}" の)
**デバッグ用関数 browser() [#y9a7133d]
-関数定義中に COLOR(red){browser()} を埋め込むと、関数の...
-関数の実行を継続するには COLOR(cred){c} を入力する。
-COLOR(red){browser()} は関数定義中に幾つおいても良い。
-COLOR(red){n} を入力すると、デバッグ付のステップ実行を開...
-COLOR(red){Q} を入力すると現在の実行を終了しトップレベル...
# browser 関数埋め込み例
> foo <- function(x, y) {z <- x*y; browser(); w <- x + y...
> a <- foo(2,3) # 関数実行
Called from: foo(2, 3) # 中断メッセージ
Browse[1]> ls() # 現在の環境内のオブジェクト...
[1] "x" "y" "z"
Browse[1]> x # 変数 x の値は?
[1] 2
Browse[1]> y
[1] 3
Browse[1]> z
[1] 6
Browse[1]> w # 変数 w はこの時点では存在...
Error: Object "w" not found
Browse[1]> c # 関数実行継続
> a$z
[1] 6
> a$w
[1] 5
**デバッグ用関数 debug() [#d38040ad]
-関数 COLOR(red){debug()} はその引数である関数にデバッグ...
-デバッグ用フラグが建てられた関数が入力されると、正常な実...
-各段階で新しい内容ブラウザが起動される
-次のステップに移るためには、キャリッジリターン、COLOR(re...
-変量の値はその名前をタイプすると見ることが出来る
-COLOR(red){c} または COLOR(red){cont} をタイプするとデバ...
-デバッガーの内部から、新しい関数を、それに踏み込む前に ...
-COLOR(red){Q} をタイプすると現在の実行を中止でき、トップ...
-COLOR(red){where} とタイプすると、デバッガーは現在のスタ...
-もし制御文字(例えば、COLOR(red){c} や COLOR(rd){n})と...
> foo <- function(x, y) {z <- x*y; w <- x + y; return(z,...
> debug(foo) # デバッグ用フラグを立てる
> foo(2,3) # 関数実行
debugging in: foo(2, 3)
debug: {
z <- x * y
w <- x + y
return(z, w)
}
Browse[1]> ls() # 現在の関数実行環境中のオブジェクト(...
[1] "x" "y"
Browse[1]> x
[1] 2
Browse[1]> n
debug: z <- x * y
Browse[1]> ls()
[1] "x" "y"
Browse[1]> n
debug: w <- x + y
Browse[1]> ls()
[1] "x" "y" "z" # 変数 z が作られている
Browse[1]> z
[1] 6
Browse[1]> n
debug: return(z, w)
Browse[1]> ls()
[1] "w" "x" "y" "z" # 変数 w も作られている
Browse[1]> w # 変数 w の値
[1] 5
Browse[1]> n
exiting from: foo(2, 3) # 関数実行終了
*その他 [#lfae448e]
**匿名関数 [#pde2ff55]
名前の無い関数があり得る。例えば関数中である特別な値を一...
> (function(z){dnorm(z)})((0:8)/2) # N(0,1) の密度関数...
[1] 0.3989422804 0.3520653268 0.2419707245 0.1295175957 ...
[6] 0.0175283005 0.0044318484 0.0008726827 0.0001338302
> foo <- function (x) {y <- (function(z){dnorm(z)})((0:8...
> foo(2)
[1] 0.7978845608 0.7041306535 0.4839414490 0.2590351913 ...
[6] 0.0350566010 0.0088636968 0.0017453654 0.0002676605
> sapply(airquality, mean) # NA を含むデータファイルの場...
Ozone Solar.R Wind Temp Month ...
NA NA 9.957516 77.882353 6.993464 15.803...
> sapply(airquality, function(x) mean(x, na.rm=TRUE)) # ...
Ozone Solar.R Wind Temp Month ...
42.129310 185.931507 9.957516 77.882353 6.993464 ...
> sapply(airquality, mean, na.rm=TRUE) # この場合には,...
Ozone Solar.R Wind Temp Month ...
42.129310 185.931507 9.957516 77.882353 6.993464 ...
**関数の再帰的定義 [#s7723b59]
関数の定義中に、その関数自身が登場しても良い。当然、登場...
> foo <- function(x) {ifelse(x==1, 1, x*foo(x-1))} # 即...
> foo(1) # 1!
[1] 1
> foo(2)
[1] 2 # 2! (foo(2) を計算する際、foo(1) は...
> foo(10)
[1] 3628800 # 10!
**関数内部での関数定義 [#uc36ab6d]
R の関数内部には別の関数定義を置き、その場で実行できる。...
> foo <- function() {
foo2 <- function() { # 関数内部での関...
x <- 1:3; y <- 23:34; z <- cbind(x, y); r...
c <- foo2() # その場で実行
return(c$z, c$x, c$y) }
> x <- foo()
> x[[2]]
[1] 1 2 3
> x[[3]]
[1] 23 24 25 26 27 28 29 30 31 32 33 34
> foo2() # 関数 foo2 ...
Error: couldn't find function "foo2"
> foo <- function (x) {
y <- x
temp <- function (a) a*y # temp 定義中...
temp(2) }
> foo(4)
[1] 8
こんなのもあり
> foo <- function(x) {
+ foo2 <- function(x) {foo3 <- function(x) x+1; foo3(x)}
+ foo2(x)}
> foo(3) # foo は foo2 を呼出し、foo2 は foo3 を呼び...
[1] 4
**二項演算子型の関数 [#f5d6ea99]
R における COLOR(red){+}, COLOR(red){-}, COLOR(red){*},...
> "%+=%" <- function(x, y) {x <<- x + y} # C 風のイン...
> x <- 10; x %+=% 5
> x
[1] 15 # x は 5 だけ増えている
注意:C だと,以下の演算と同じことをする x+= 5*7 の後,x...
> x <- 10
> x %+=% 5*7
[1] 105
> x
[1] 15
**関数を返す関数 [#m13693c4]
R の関数は R の任意のオブジェクトを返すことができる。当然...
> foo <- function(a, b) {function (x, y) a*x + b*y}
> Foo <- foo(2, 3) # Foo(x, y) は関数 2*x + 3*y
> Foo(1, 2)
[1] 8
> Foo # 定義を見る (a=1, b=2 の情報は附属環境に含まれて...
function(x,y) a*x+b*y
<environment: 0x846e354>
> Foo <- foo(-2, -3) # Foo(x, y) は関数 (-2)*x + (-3)*y
> Foo(1, 2)
[1] -8
**関数と変数(オブジェクト)のスコープ [#w9932351]
R の COLOR(magenta){スコープ規則} (ある名前のオブジェク...
-関数は固有の COLOR(magenta){附属環境} (関数固有のオブジ...
-また関数を実行した環境(COLOR(magenta){実行環境})も存在し...
-もし関数中に、その附属環境中に無い変数・オブジェクトが現...
-関数の附属環境は関数の終了とともに消え去り、その返り値は...
-関数中で永続付値されたオブジェクトは、関数の実行環境に直...
-従って、ある関数中には、その附属環境と親環境(更にはその...
-関数中で定義された関数は、それ自身の附属環境を新規にもつ...
> x <- 3 # 関数 foo の実行環境中...
> foo <- function (x) { # 関数 foo はその実行環境中の...
+ y <- 5 # 関数 foo の附属環境中...
# 関数 foo2 は foo の附属環境中のオブジェクト、変数 z ...
# foo2 を計算する際、x と y (とその値)はその親環境のも...
+ foo2 <- function(z) {x+y+z} + foo2(4)}
> foo(1) # x+y+z=1+5+4 を計算
[1] 10
** 後始末 on.exit() [#bf893ed8]
on.exit(EXPR) は関数が正常・異常終了した際に EXPR を実行...
> foo <- function() {
old.par <- par(no.readonly = TRUE) # 現在の作図パ...
on.exit(par(oldpar) # 関数終了時に元に戻す
on.exit(dev.off(), add=TRUE) # 更に、関数終了時に...
png("foo.png") # png デバイスを開く
--- 幾つかの作図命令 ---
}
**総称的関数とメソッド (2004.4.19) [#s774bd34]
R 言語で頻繁に使われる plot() 等の関数は総称的(generic)な...
これらの関数は引数である R オブジェクト x に応じて、実際...
# 例:総称的関数とメソッド
> methods(plot) # 総称的関数 plot() に対するメソッドの...
[1] plot.HoltWinters* plot.POSIXct plot.POSIXlt
[4] plot.TukeyHSD plot.acf* plot.data.f...
(途中略)
[28] plot.table plot.ts plot.tskern...
Non-visible functions are asterisked
> methods(class = "lm") # クラス "lm" のオブジェクトに適...
[1] add1.lm alias.lm anova.lm ...
[5] coef.lm confint.lm cooks.distance....
(途中略)
[33] variable.names.lm vcov.lm
** 関数定義時の状況で中身が変わる関数 (2004.12.09) [#n254...
例えば Unix と MS Windows では仕様が異なる関数を統一的に...
> .Platform$OS.type # 使用OS情報
[1] "unix"
> foo <- if (.Platform$OS.type = "unix" ) {function() ca...
else {function() cat("Maybe using MS Windows?\n...
*関数のチューンナップ [#db9e4a7f]
**関数の実行速度の計測 system.time() [#x7d07645]
> system.time(for (i in 1:10000) mean(runif(500)))
[1] 2.00 0.06 4.15 0.00 0.00
時間関数の返すベクトルは順に (最後の二つは普通ゼロ)
-ユーザーCPUタイム
-システムCPUタイム
-経過時間
-副プロセスの使用ユーザーCPUタイム
-副プロセスの使用システムCPUタイム
-時間の解像度はシステム固有であり、普通 1/100 秒。経過時...
**速度の向上 [#r92f0d8b]
Rは所詮インタプリター言語であり、コンパイラー型言語に比べ...
***むき出しの論理判断はできるだけ避ける [#pe2011bf]
論理判断は如何なる言語でも相対的に時間を食う。避けられな...
> foo <- function(x) {if(x<=0) return(-x) else return(x)...
> system.time(for (i in 1:100000) {x=runif(1)-0.5; foo(x...
[1] 2.44 0.06 2.80 0.00 0.00
> system.time(for (i in 1:100000) {x=runif(1)-0.5; abs(x...
[1] 1.90 0.01 2.16 0.00 0.00
> system.time(for (i in 1:100000) {x=runif(1)-0.5; sqrt(...
[1] 2.31 0.04 2.55 0.00 0.00
> system.time(for (i in 1:100000) {x=runif(1)-0.5; max(x...
[1] 2.29 0.08 2.61 0.00 0.00
> foo <- function (x) {ifelse (x==0, 1, 0)} # 引数 x は...
> x <- floor(2*runif(100000)) # 長さ 10000 の 0, 1 ベ...
> system.time(foo(x))
[1] 0.54 0.02 0.59 0.00 0.00
> foo2 <- function (x) 1-x # 実は foo と同値
> system.time(foo2(x))
[1] 0.00 0.01 0.01 0.00 0.00
***for ループはできるだけ避ける [#od24c63e]
R はベクトル・配列演算を内部 C ルーティンで処理し、高速に...
> foo <- function (X, Y) { # 二つの 100x100 行列の愚...
Z <- matrix(0,ncol=100, nrow=100)
for (i in 1:100)
for (j in 1:100)
for (k in 1:100) Z[i,j] <- Z[i,j] + X[i,...
Z}
> X <- matrix(runif(10000), ncol=100) # 100x100 行列を...
> Y <- matrix(runif(10000), ncol=100) # 同上
> system.time(Z<-foo(X, Y))
[1] 23.05 0.00 23.54 0.00 0.00
> system.time(Z <- X%*%Y) # 専用演算子を使用
[1] 0 0 0 0 0 # 一瞬!
***適切な関数を使う [#bde725bf]
上の例に出てくる 0/1 ベクトルを作るのには,最適な関数があ...
> system.time(x <- floor(2*runif(10000000)))
ユーザ システム 経過
0.804 0.216 1.015
> system.time(y <- sample(0:1, 10000000, replace=TRUE))
ユーザ システム 経過
0.432 0.102 0.531
**コードのボトルネックの発見 Rprof() [#j5e7c62d]
関数の実行速度をあげるためには、どの部分で時間を喰ってい...
> Rprof() # 既定のログファイル Rprof.out とサンプリン...
> x <- y <- matrix(runif(10^6),ncol=1000) # 大きな行列
> z <- x%*%y # その掛け算
> Rprof(NULL) # プロファイル終了
> summaryRprof() # 既定のログファイル Rprof.out からプ...
$by.self
self.time self.pct total.time total.pct
"%*%" 2.26 71.5 2.26 71.5 # 行列掛け算がや...
"runif" 0.42 13.3 0.42 13.3 # 一様乱数生...
"as.vector" 0.24 7.6 0.66 20.9 # (恐らく) ベク...
"matrix" 0.24 7.6 0.90 28.5 # (恐らく) ベ...
$by.total
total.time total.pct self.time self.pct
"%*%" 2.26 71.5 2.26 71.5
"matrix" 0.90 28.5 0.24 7.6
"as.vector" 0.66 20.9 0.24 7.6
"runif" 0.42 13.3 0.42 13.3
$sampling.time
[1] 3.16
**使い勝手の向上 [#m7acd859]
使い勝手の向上はしばしば速度と反比例するが、より好ましい...
***関数のベクトル化 [#l7f41e62]
R の多くの組み込み関数は意味がある限りできるだけベクトル...
> x=1:10 # 等差数列
> x^2
[1] 1 4 9 16 25 36 49 64 81 100 # 巾乗関数...
> x <- matrix(1:16, ncol=4)
> x^2 # それどころか行列化され...
[,1] [,2] [,3] [,4] # 実は R では配列は特殊...
[1,] 1 25 81 169
[2,] 4 36 100 196
[3,] 9 49 121 225
[4,] 16 64 144 256
> choose(10, 0:10) # 二項係数もベクトル化されている!
[1] 1 10 45 120 210 252 210 120 45 10 1
> choose(10:13, 10)
[1] 1 11 66 286
> choose(10:13, 0:10) # はてこれは何を計算してくれたの...
[1] 1 11 66 286 210 462 924 1716 45 55 ...
> runif(10)>0.5 # 論理判断もベクトル化され...
[1] TRUE TRUE TRUE FALSE FALSE FALSE TRUE FALSE FAL...
ベクトル化された式だけを使えば結果は自然にベクトル化され...
> foo <- function (x) sin(x>0.5) # R では論理値 TRUE, F...
> foo(runif(10))
[1] 0.000000 0.841471 0.000000 0.000000 0.841471 0.0000...
[9] 0.841471 0.841471
無理矢理ベクトル化する方法の例
> foo <- function(x) if (x<0) return(2) else return(3) ...
> foo(runif(10) - 0.5) # x の最初の要素だけ受け付ける
[1] 2
Warning message:
the condition has length > 1 and only the first element ...
...
> foo <- function (x) { # そのベクトル化版
temp <- function(x) if (x<0) return(2) e...
sapply(x, temp) } # sapply 関数は x の...
> foo(runif(10)-0.5)
[1] 2 2 2 2 3 3 3 3 2 2
> ifelse(runif(10) - 0.5 < 0, 2, 3) # 実はベクトル化さ...
[1] 3 2 2 3 3 3 3 3 2 2
> (2:3)[(runif(10) < 0.5)+1] # トリッキーな方法を追加
[1] 2 3 2 3 3 3 2 2 3 3
***引数のチェック [#j1a8a96b]
引数には自然な制約条件があることもある。そうした場合、範...
***途中の演算結果の妥当性のチェック [#m3b01d3f]
演算途中の変数値にも自然な制約範囲があることがある。もし...
***既定値つき変数の利用 [#icf88831]
幾つかの変数には容易に意味が分かる名前を付け、合理的な既...
***コードへのコメント [#oe6d4772]
他人が使う可能性のあるコードには積極的にコメントを要所要...
***複雑な関数はできるだけ細分化する [#a42626b9]
必要な機能を細分、パーツ化し小関数化する(Unix 精神)。
短い関数はチェックがし易い。また既に既成のものが存在する...
***過度の最適化は避ける [#yf48dd28]
できるだけ短くしたエレガントなコード、速度を最適化したア...
***関数は二度書く [#cc3851bf]
苦労して書いた関数は、しばしばスパゲッティコードになり、...
終了行:
#contents
//間瀬茂
*本項目について [#t2db350f]
R での処理は一連の関数を用いて行なわれます。
既に多くの関数が定義されており、それだけでも一通りの解析...
R には、最初から関数を簡便に定義するための多くの便利な機...
いずれにしても、一旦定義されれば、自前の関数も、R 固有の...
//(ほぼ完成かな。後は自由に修正、追加お願いします。
//間瀬 (2003/6/28)
*関数定義の基本書式 [#j5769b89]
> foo <- function(引数リスト) 関数本体 # 関数本体が一...
> foo <- function(引数リスト) {関数本体} # 関数本体が複...
> "foo" <- function(引数リスト) 関数本体 # この形式もあ...
警告:COLOR(red){R の組み込み関数は自由に再定義可能}であ...
*本体 [#d0f74300]
関数本体は R の式を必要なだけ並べたものです。一つの行に複...
# 例
> foo <- function(x, y) { # foo という名前の関数を二つ...
z <- x + y; w <- x * y # セミコロンで区...
if (z > w) t <- z # 好みで if (...
else {t <- w; w <- z; z <-t} # 波括弧で...
for (i in 1:10) { w <- w + i; z <- z - i}
cat("z = ", z, " w = ", w, "?n")
return (list(w, z)) # 二つの返り値
}
> foo(2, 3) # すぐ実行できる
*引数 [#if5c32ea]
**引数リスト [#w1f86bdf]
-引数リストはコンマで区切った(仮)引数名のリスト
> foo <- function () cat("R is fantastic! ?n") # 引数なし
> foo1 <- function (x) x^2 # 引数一つ(自乗値を計算)
> foo2 <- function (x,y) x*y # 引数二つ(積を計算)
> foo3 <- function (x,y,z) { # 引数3つ(本体が長いので括...
w <- exp(x)*(y+z)
cat("x=",x,"y=",y,"z=",z, "result=",w)
}
**名前・既定値つきの引数 (2004.8.13) [#lbada251]
-COLOR(red){引数名=既定値} の形式で既定値を指定できる(関...
> foo <- function(x=1, y=2) x+y # 既定値つき(名前つ...
> foo() # 既定値 x=1, y=2 と解釈
[1] 3
> foo(0.1, 20) # x=0.1, y=20 と解釈
[1] 20.1
> foo(x=0) # 既定値 y=2 が使われる
[1] 2
> foo(y=0) # 既定値 x=2 が使われる
[1] 1
> foo(x=5, y=6)
[1] 11
> foo(6) # 既定値 y=2 が使われる
[1] 8
> foo(6,) # 上と同じ
[1] 8
> foo(,6) # 既定値 x=1 が使われる
[1] 7
次のような(場合により値が異なる)既定値つきの引数を与える...
> test <- function (x, y=ifelse(x>=0, 1, -1)) {cat(x,y,"...
> test(1, 2) # y 引数を与えればそれが第二引数の値になる
1 2
> test(1) # y 引数を省略すると、x 引数に応じた既定値が第...
1 1
> test(-1)
-1 -1
digitsBase(x, base = 2, ndigits = 1 + floor(log(max(x), ...
という関数は次の様にさまざまな引数の与え方で実行できる
(1) digitsBase(10) base と ndigits は既定値が使われる
(2) digitsBase(10, base = 8) base と ndigits は既定値が...
(3) digitsBase(10, ndigits = 5) base に既定値 2 が使われる
(4) digitsBase(10, base = 8, ndigits = 5) 既定値なし
-名前つき引数指定 option = value では、引数名 option は一...
関数 foo <- function (x, mab = 3, mbc = 0.1, bar = 10) {...
foo(3)
foo(3, ma=4, mb=1)
foo(3, b=4)
-関数の実際の呼出しにおいて、複数の引数は名前付きで与える...
-COLOR(red){注意}:名前つきでない引数も実際は暗黙の内にCO...
> test <- function(x,y) print(x+y)
> test(1,2)
[1] 3
> test(x=1,2)
[1] 3
> test(1,y=2)
[1] 3
> test(x=1,y=2)
[1] 3
> test(y=2, x=1)
[1] 3
**引数として関数オブジェクトを与える場合 (2004/09/15) [#n...
引数として関数オブジェクトを与えることができる。
普通関数オブジェクト名を引数として与える:
test <- function(x, fun=sin) {plot(x, fun(x))}
test(1:100/100) # 既定の関数 sin ...
test(x, fun=cos) # 関数として cos ...
test(x, fun=function(z) 1/(1+exp(z))) # 関数定義を直接与...
関数自身がオプション引数をもち、それを特定の値に指定した...
util <- function(x , opta=1, optb=0) # オプ...
test(1:100/100, fun=test(x, opta=10, optb=-1) ) # エラ...
my.util <- function(x) util(x, opta=10, optb=-1) # オプ...
test(1:100/100, fun=my.util) # 正し...
# もしくは引数として関数定義を直接書いても良い
test(1:100/100, fun=function(x) util(x, opta=10, optb=-1))
**特別な(その他大勢)引数 ... (2004.8.13) [#pdfd1871]
-特別な引数として COLOR(red){...} が使える.これは任意の...
> foo <- function(x, ...) {
if (x >= 0) return(x*cos(...[1]) + x^2*sin(...
else return(exp(x))}
> foo(1,c(2,3)) # ... にベクトル値
[1] -0.2750268
> foo(-1) # ... 部分の引数無し。実際この場合...
[1] 0.3678794
-特殊引数 COLOR(red){...} は関数引数欄の最後におかれるの...
この特徴は面倒のようにも思えるが、COLOR(red){...} 引数は...
> test1 <- function(x, y=3, ...) (x+...[1])^y
> test2 <- function(x, ..., y=3) (x+...[1])^y # ... 引...
> test1(1); test2(1)
[1] 8 # = (1+1)^3
[1] 8 # = (1+1)^3 # ...[1] = 1 とされている (?)
> test1(1,2); test2(1,2)
[1] 4 # (1+1)^2
[1] 27 # (1+2)^3 # ...[1] = 2 とされている (問...
> test1(1,2,3)
[1] 16 # (1+3)^3
> test2(1,2,3) # ... 引数の後の引数は名前付き...
Error in ...[1] : incorrect number of dimensions
> test2(1,2,y=3)
[1] 27 # (1+2)^3 # y 引数を名前付きで与えた (問...
参考: ... 引数は関数引数欄に明示的に与えなくても不思議...
> test3 <- function(x, y=3, ...) print(...[1])
> test3(1)
[1] 1 # ...[1] = 1 とされている
> test3(3,2)
[1] 1 # ...[1] = 1 とされている
> test3(3,2,1)
[1] 1 # ...[1] = 1 とされている
> test4 <- function(x, y=3, ...) print(c(...[1],...[2],....
> test4(3)
[1] 1 2 3 # ... = c(1,2,3) とされている
その他大勢引数が実際は複数の引数になるとき、k 番目の項目...
> test <- function(i,...) print(list(...)[[i]])
> test(1,1,"abc",list(1:4),matrix(1:4,2,2))
[1] 1
> test(2,1,"abc",list(1:4),matrix(1:4,2,2))
[1] "abc"
> test(3,1,"abc",list(1:4),matrix(1:4,2,2))
[[1]]
[1] 1 2 3 4
> test(4,1,"abc",list(1:4),matrix(1:4,2,2))
[,1] [,2]
[1,] 1 3
[2,] 2 4
従って ... 引数が実際は幾つの引数かを知るには length(list...
*返り値 [#x4f3db54]
関数は返り値を持っても良いし、持たなくてもよい。返り値の...
**暗黙の返り値 [#w6ff162e]
もし COLOR(red){return()}, COLOR(red){invisible()} 関数に...
> foo1 <- function (x) x^2 # x^2 の値が暗黙の返り値
**返り値関数 return() [#sd01cac7]
-関数本体に COLOR(red){return()} を置くとその中身が返り値...
-COLOR(red){return()} が複数あっても良いが,いずれかの CO...
> foo <- function (x,y) {return(x+y)}
> foo(1,2)
[1] 3 # x+y が返り値
> foo <- function (x, y) {return(x); cat("sum =", x+y)}
> foo(1,2) # cat は実行されない
[1] 1
> foo <- function (x,y) {if (x>=y) return(x) else return...
> foo(1,2)
[1] 2
> foo(2,1)
[1] 2
**複数の返り値 return() [#mea7984c]
-COLOR(red){return()} 関数の中に,複数の値を置くと,返り...
-リスト成分には名前ラベルを与えることができる
- COLOR(red){この機能は将来廃止されるらしく、R.1.8 からは...
-上の記述はミスリード。return(c(x, y, x+y)) のように、ベ...
> foo <- function (x,y) {return(x,y,x+y)}
> res <- foo(1,2)
> res[[1]]
[1] 1
> res[[2]]
[1] 2
> res[[3]]
[1] 3
> foo <- function (x,y) {return(x=x,y=y,sum=x+y)} # ラ...
> res <- foo(1,2)
> res$x # res[[1]], res[["x"]] でも良い
[1] 1
> res$y # res[[2]], res[["y"]] でも良い
[1] 2
> res$sum # res[[3]], res[["sum"]] でも良い
[1] 3
**コンソールに表示されない返り値 invisible() [#g4f10798]
例えば、非常に大量で、可読性の低い値を返す関数を考えると...
> foo <- functionn (x) return(x)
> foo(1)
[1] 1
> foo <- functionn (x) invisible(x)
> foo(1) # 何も表示されない
> x <- foo(1)
> x # 結果は変数 x に付値されている
[1] 1
COLOR(red){注意}:invisible() 関数は関数の返り値の指定に...
> test <- function(x) {print(x); x <- x+1; x}
> test(3)
[1] 3 # print(x) による出力
[1] 4 # 関数 test の返り値
> temp <- invisible(test(3))
[1] 3
> temp
[1] 4
**途中結果を返す (2004.8.13) [#i0fcbb7d]
普通最後の結果だけが返り値になるという特徴は、途中結果を...
解決策は必要な途中結果を print(), cat() 関数でコンソール...
# 途中結果を print() 関数でコンソールに出力する
> test <- function(x) {for (i in 1:3) print(x+i)}
> test(3)
[1] 4
[1] 5
[1] 6
> temp <- test(3)
[1] 4
[1] 5
[1] 6
> temp # しかし返り値は依然として最後のものだけ
[1] 6
途中結果をベクトルに貯めておき、最後に返り値とするやりかた
> test2 <- function(x) {res <- numeric(0); for (i in 1:3...
> test2(3)
> test2 <- function(x) {res <- numeric(0); for (i in 1:3...
> test2(3)
[1] 4 5 6 # 途中結果のベクトル返り値
結果として返す値の個数(ベクトルの要素数)がわかっている...
> test9 <- function(n) {res <- numeric(n); for(i in 1:n)...
> test9(10)
**永続付値演算子で間接的に返り値を返す(健康のために使い過...
関数中で永続付値演算子を使うと、関数終了後も残る値を変数...
> v <- 1
> test <- function () {v <- 2; v <<- 3; cat("v=", v, "\n...
> test()
v= 2
> v # いつのまにか値が変わっている
[1] 3
この例では関数内部での変数 COLOR(red){v} と永続付値で生成...
もう少し微妙な例:
> test <- function () {v <- 1:3; v[2] <<- 0; cat("v=", v...
> test()
v= 1 2 3 # 局所的な v の値
> v
[1] 1 0 3 # 大局的な変数 v がつくり出され、いつの間にか...
大局的変数への永続付値の便利な使い方は、他の関数で使うべ...
> foo <- function (x, y, z) {.w <<- list(x, y, z)} ...
> foo2 <- function () {.w[[1]] + .w[[2]] + .w[[3]]} # ...
> foo(1, 2, 3) # これで大局的変数 .w (=list(1 , 2, 3)...
> foo2()
[1] 6
COLOR(magenta){教訓: 関数中の永続付値は便利だが使用には注...
** 特定の環境に値を返す (2004.09.30) [#h9d79ab0]
R のすべての実行式は対応する環境を持つ。普通重要になる環...
# 関数の実行環境の親環境(その関数を呼び出した環境)に登録
# mat <<- mat と同じことになる
assign("mat", mat, parent.frame())
assign("mat", mat, .GlobalEnv) # 大局的環境に登録
*エラー処理 [#v56a9451]
**stop() 関数 [#f2de2144]
COLOR(red){stop()} 関数は、現在の式の実行を中断し、その引...
# x が負またはゼロなら中断、正なら log(x) を返す関数
> foo <- function(x) ifelse( x<=0, stop(message="non-pos...
> foo(3)
[1] 1.098612
> foo(-3)
Error in rep(yes, length = length(ans)) : non-positive a...
**warning() 関数 [#o9dcb1ff]
警告メッセージを生成する。 実際の結果は options("warn") ...
-warn が負なら警告は無視される
-warn が零ならば一旦保存され、最上位の関数が終了した際に...
-warn が 1 ならば警告が生起するとすぐに出力され、 2 (もし...
> foo <- function(x) {
if (x<=0) {return(NA); warning(message="NA pr...
else return(log(x)
}
> foo(3)
[1] 1.098612
> foo(-3)
Error in rep(yes, length = length(ans)) : non-positive a...
-結果は COLOR(red){options("warn")} の値に依存する
-もし warn が負なら警告は無視される
-もしそれが零ならば一旦保存され 最上位の関数が終了した際...
-もしそれが 1 ならば警告が生起するとすぐに出力される
-2(もしくはそれ以上)ならば警告はエラーとして処理される。
**stopifnot() 関数(2004/08/14) [#z7955236]
引数としてカンマで区切って並べられた条件が満たされないと...
(stopif という関数仕様の方が素直で便利だと思うのだが)
> a <-3
> b <- 4
:
> stopifnot(a == 3, b==5)
Error: b == 5 is not TRUE
*関数のデバッグ [#x2e0a733]
デバッグは困難な問題であるが、最大の困難ではない。デバッ...
**万能デバッグ関数 cat() [#fe61b76f]
最も安易な関数のデバッグ法は、関数中に COLOR(red){cat()} ...
> foo <- function (x) {
cat("arg x=", x, "?n")
log(x) }
> foo(-1)
arg x= -1 # デバッグメッセージ (なるほど log 関数は...
[1] NaN
Warning message:
NaNs produced in: log(x)
デバッグ用に COLOR(red){cat()} を沢山埋め込んだ後は、すぐ...
> foo <- function (x) {
#cat("arg x=", x, "?n") # 一行コメント...
log(x) }
> foo <- function (x, y) {
if (0) { cat("1st arg =", x, "?n")
cat("2nd arg =", y, "?n") } # 二...
log(x)*log(y) }
注意:if (0) { と } の中には,R の文法上正しいものしか書...
> bar <- function(x) {
+ if (0) {
+ この行はエラーにならないけど,次の行はエラーになる(...
> x <- b±root(b2-4ac)
> }
エラー: 予想外の '}' です ( " }" の)
> return(x+1)
エラー: オブジェクト 'x' がありません
> }
エラー: 予想外の '}' です ( "}" の)
**デバッグ用関数 browser() [#y9a7133d]
-関数定義中に COLOR(red){browser()} を埋め込むと、関数の...
-関数の実行を継続するには COLOR(cred){c} を入力する。
-COLOR(red){browser()} は関数定義中に幾つおいても良い。
-COLOR(red){n} を入力すると、デバッグ付のステップ実行を開...
-COLOR(red){Q} を入力すると現在の実行を終了しトップレベル...
# browser 関数埋め込み例
> foo <- function(x, y) {z <- x*y; browser(); w <- x + y...
> a <- foo(2,3) # 関数実行
Called from: foo(2, 3) # 中断メッセージ
Browse[1]> ls() # 現在の環境内のオブジェクト...
[1] "x" "y" "z"
Browse[1]> x # 変数 x の値は?
[1] 2
Browse[1]> y
[1] 3
Browse[1]> z
[1] 6
Browse[1]> w # 変数 w はこの時点では存在...
Error: Object "w" not found
Browse[1]> c # 関数実行継続
> a$z
[1] 6
> a$w
[1] 5
**デバッグ用関数 debug() [#d38040ad]
-関数 COLOR(red){debug()} はその引数である関数にデバッグ...
-デバッグ用フラグが建てられた関数が入力されると、正常な実...
-各段階で新しい内容ブラウザが起動される
-次のステップに移るためには、キャリッジリターン、COLOR(re...
-変量の値はその名前をタイプすると見ることが出来る
-COLOR(red){c} または COLOR(red){cont} をタイプするとデバ...
-デバッガーの内部から、新しい関数を、それに踏み込む前に ...
-COLOR(red){Q} をタイプすると現在の実行を中止でき、トップ...
-COLOR(red){where} とタイプすると、デバッガーは現在のスタ...
-もし制御文字(例えば、COLOR(red){c} や COLOR(rd){n})と...
> foo <- function(x, y) {z <- x*y; w <- x + y; return(z,...
> debug(foo) # デバッグ用フラグを立てる
> foo(2,3) # 関数実行
debugging in: foo(2, 3)
debug: {
z <- x * y
w <- x + y
return(z, w)
}
Browse[1]> ls() # 現在の関数実行環境中のオブジェクト(...
[1] "x" "y"
Browse[1]> x
[1] 2
Browse[1]> n
debug: z <- x * y
Browse[1]> ls()
[1] "x" "y"
Browse[1]> n
debug: w <- x + y
Browse[1]> ls()
[1] "x" "y" "z" # 変数 z が作られている
Browse[1]> z
[1] 6
Browse[1]> n
debug: return(z, w)
Browse[1]> ls()
[1] "w" "x" "y" "z" # 変数 w も作られている
Browse[1]> w # 変数 w の値
[1] 5
Browse[1]> n
exiting from: foo(2, 3) # 関数実行終了
*その他 [#lfae448e]
**匿名関数 [#pde2ff55]
名前の無い関数があり得る。例えば関数中である特別な値を一...
> (function(z){dnorm(z)})((0:8)/2) # N(0,1) の密度関数...
[1] 0.3989422804 0.3520653268 0.2419707245 0.1295175957 ...
[6] 0.0175283005 0.0044318484 0.0008726827 0.0001338302
> foo <- function (x) {y <- (function(z){dnorm(z)})((0:8...
> foo(2)
[1] 0.7978845608 0.7041306535 0.4839414490 0.2590351913 ...
[6] 0.0350566010 0.0088636968 0.0017453654 0.0002676605
> sapply(airquality, mean) # NA を含むデータファイルの場...
Ozone Solar.R Wind Temp Month ...
NA NA 9.957516 77.882353 6.993464 15.803...
> sapply(airquality, function(x) mean(x, na.rm=TRUE)) # ...
Ozone Solar.R Wind Temp Month ...
42.129310 185.931507 9.957516 77.882353 6.993464 ...
> sapply(airquality, mean, na.rm=TRUE) # この場合には,...
Ozone Solar.R Wind Temp Month ...
42.129310 185.931507 9.957516 77.882353 6.993464 ...
**関数の再帰的定義 [#s7723b59]
関数の定義中に、その関数自身が登場しても良い。当然、登場...
> foo <- function(x) {ifelse(x==1, 1, x*foo(x-1))} # 即...
> foo(1) # 1!
[1] 1
> foo(2)
[1] 2 # 2! (foo(2) を計算する際、foo(1) は...
> foo(10)
[1] 3628800 # 10!
**関数内部での関数定義 [#uc36ab6d]
R の関数内部には別の関数定義を置き、その場で実行できる。...
> foo <- function() {
foo2 <- function() { # 関数内部での関...
x <- 1:3; y <- 23:34; z <- cbind(x, y); r...
c <- foo2() # その場で実行
return(c$z, c$x, c$y) }
> x <- foo()
> x[[2]]
[1] 1 2 3
> x[[3]]
[1] 23 24 25 26 27 28 29 30 31 32 33 34
> foo2() # 関数 foo2 ...
Error: couldn't find function "foo2"
> foo <- function (x) {
y <- x
temp <- function (a) a*y # temp 定義中...
temp(2) }
> foo(4)
[1] 8
こんなのもあり
> foo <- function(x) {
+ foo2 <- function(x) {foo3 <- function(x) x+1; foo3(x)}
+ foo2(x)}
> foo(3) # foo は foo2 を呼出し、foo2 は foo3 を呼び...
[1] 4
**二項演算子型の関数 [#f5d6ea99]
R における COLOR(red){+}, COLOR(red){-}, COLOR(red){*},...
> "%+=%" <- function(x, y) {x <<- x + y} # C 風のイン...
> x <- 10; x %+=% 5
> x
[1] 15 # x は 5 だけ増えている
注意:C だと,以下の演算と同じことをする x+= 5*7 の後,x...
> x <- 10
> x %+=% 5*7
[1] 105
> x
[1] 15
**関数を返す関数 [#m13693c4]
R の関数は R の任意のオブジェクトを返すことができる。当然...
> foo <- function(a, b) {function (x, y) a*x + b*y}
> Foo <- foo(2, 3) # Foo(x, y) は関数 2*x + 3*y
> Foo(1, 2)
[1] 8
> Foo # 定義を見る (a=1, b=2 の情報は附属環境に含まれて...
function(x,y) a*x+b*y
<environment: 0x846e354>
> Foo <- foo(-2, -3) # Foo(x, y) は関数 (-2)*x + (-3)*y
> Foo(1, 2)
[1] -8
**関数と変数(オブジェクト)のスコープ [#w9932351]
R の COLOR(magenta){スコープ規則} (ある名前のオブジェク...
-関数は固有の COLOR(magenta){附属環境} (関数固有のオブジ...
-また関数を実行した環境(COLOR(magenta){実行環境})も存在し...
-もし関数中に、その附属環境中に無い変数・オブジェクトが現...
-関数の附属環境は関数の終了とともに消え去り、その返り値は...
-関数中で永続付値されたオブジェクトは、関数の実行環境に直...
-従って、ある関数中には、その附属環境と親環境(更にはその...
-関数中で定義された関数は、それ自身の附属環境を新規にもつ...
> x <- 3 # 関数 foo の実行環境中...
> foo <- function (x) { # 関数 foo はその実行環境中の...
+ y <- 5 # 関数 foo の附属環境中...
# 関数 foo2 は foo の附属環境中のオブジェクト、変数 z ...
# foo2 を計算する際、x と y (とその値)はその親環境のも...
+ foo2 <- function(z) {x+y+z} + foo2(4)}
> foo(1) # x+y+z=1+5+4 を計算
[1] 10
** 後始末 on.exit() [#bf893ed8]
on.exit(EXPR) は関数が正常・異常終了した際に EXPR を実行...
> foo <- function() {
old.par <- par(no.readonly = TRUE) # 現在の作図パ...
on.exit(par(oldpar) # 関数終了時に元に戻す
on.exit(dev.off(), add=TRUE) # 更に、関数終了時に...
png("foo.png") # png デバイスを開く
--- 幾つかの作図命令 ---
}
**総称的関数とメソッド (2004.4.19) [#s774bd34]
R 言語で頻繁に使われる plot() 等の関数は総称的(generic)な...
これらの関数は引数である R オブジェクト x に応じて、実際...
# 例:総称的関数とメソッド
> methods(plot) # 総称的関数 plot() に対するメソッドの...
[1] plot.HoltWinters* plot.POSIXct plot.POSIXlt
[4] plot.TukeyHSD plot.acf* plot.data.f...
(途中略)
[28] plot.table plot.ts plot.tskern...
Non-visible functions are asterisked
> methods(class = "lm") # クラス "lm" のオブジェクトに適...
[1] add1.lm alias.lm anova.lm ...
[5] coef.lm confint.lm cooks.distance....
(途中略)
[33] variable.names.lm vcov.lm
** 関数定義時の状況で中身が変わる関数 (2004.12.09) [#n254...
例えば Unix と MS Windows では仕様が異なる関数を統一的に...
> .Platform$OS.type # 使用OS情報
[1] "unix"
> foo <- if (.Platform$OS.type = "unix" ) {function() ca...
else {function() cat("Maybe using MS Windows?\n...
*関数のチューンナップ [#db9e4a7f]
**関数の実行速度の計測 system.time() [#x7d07645]
> system.time(for (i in 1:10000) mean(runif(500)))
[1] 2.00 0.06 4.15 0.00 0.00
時間関数の返すベクトルは順に (最後の二つは普通ゼロ)
-ユーザーCPUタイム
-システムCPUタイム
-経過時間
-副プロセスの使用ユーザーCPUタイム
-副プロセスの使用システムCPUタイム
-時間の解像度はシステム固有であり、普通 1/100 秒。経過時...
**速度の向上 [#r92f0d8b]
Rは所詮インタプリター言語であり、コンパイラー型言語に比べ...
***むき出しの論理判断はできるだけ避ける [#pe2011bf]
論理判断は如何なる言語でも相対的に時間を食う。避けられな...
> foo <- function(x) {if(x<=0) return(-x) else return(x)...
> system.time(for (i in 1:100000) {x=runif(1)-0.5; foo(x...
[1] 2.44 0.06 2.80 0.00 0.00
> system.time(for (i in 1:100000) {x=runif(1)-0.5; abs(x...
[1] 1.90 0.01 2.16 0.00 0.00
> system.time(for (i in 1:100000) {x=runif(1)-0.5; sqrt(...
[1] 2.31 0.04 2.55 0.00 0.00
> system.time(for (i in 1:100000) {x=runif(1)-0.5; max(x...
[1] 2.29 0.08 2.61 0.00 0.00
> foo <- function (x) {ifelse (x==0, 1, 0)} # 引数 x は...
> x <- floor(2*runif(100000)) # 長さ 10000 の 0, 1 ベ...
> system.time(foo(x))
[1] 0.54 0.02 0.59 0.00 0.00
> foo2 <- function (x) 1-x # 実は foo と同値
> system.time(foo2(x))
[1] 0.00 0.01 0.01 0.00 0.00
***for ループはできるだけ避ける [#od24c63e]
R はベクトル・配列演算を内部 C ルーティンで処理し、高速に...
> foo <- function (X, Y) { # 二つの 100x100 行列の愚...
Z <- matrix(0,ncol=100, nrow=100)
for (i in 1:100)
for (j in 1:100)
for (k in 1:100) Z[i,j] <- Z[i,j] + X[i,...
Z}
> X <- matrix(runif(10000), ncol=100) # 100x100 行列を...
> Y <- matrix(runif(10000), ncol=100) # 同上
> system.time(Z<-foo(X, Y))
[1] 23.05 0.00 23.54 0.00 0.00
> system.time(Z <- X%*%Y) # 専用演算子を使用
[1] 0 0 0 0 0 # 一瞬!
***適切な関数を使う [#bde725bf]
上の例に出てくる 0/1 ベクトルを作るのには,最適な関数があ...
> system.time(x <- floor(2*runif(10000000)))
ユーザ システム 経過
0.804 0.216 1.015
> system.time(y <- sample(0:1, 10000000, replace=TRUE))
ユーザ システム 経過
0.432 0.102 0.531
**コードのボトルネックの発見 Rprof() [#j5e7c62d]
関数の実行速度をあげるためには、どの部分で時間を喰ってい...
> Rprof() # 既定のログファイル Rprof.out とサンプリン...
> x <- y <- matrix(runif(10^6),ncol=1000) # 大きな行列
> z <- x%*%y # その掛け算
> Rprof(NULL) # プロファイル終了
> summaryRprof() # 既定のログファイル Rprof.out からプ...
$by.self
self.time self.pct total.time total.pct
"%*%" 2.26 71.5 2.26 71.5 # 行列掛け算がや...
"runif" 0.42 13.3 0.42 13.3 # 一様乱数生...
"as.vector" 0.24 7.6 0.66 20.9 # (恐らく) ベク...
"matrix" 0.24 7.6 0.90 28.5 # (恐らく) ベ...
$by.total
total.time total.pct self.time self.pct
"%*%" 2.26 71.5 2.26 71.5
"matrix" 0.90 28.5 0.24 7.6
"as.vector" 0.66 20.9 0.24 7.6
"runif" 0.42 13.3 0.42 13.3
$sampling.time
[1] 3.16
**使い勝手の向上 [#m7acd859]
使い勝手の向上はしばしば速度と反比例するが、より好ましい...
***関数のベクトル化 [#l7f41e62]
R の多くの組み込み関数は意味がある限りできるだけベクトル...
> x=1:10 # 等差数列
> x^2
[1] 1 4 9 16 25 36 49 64 81 100 # 巾乗関数...
> x <- matrix(1:16, ncol=4)
> x^2 # それどころか行列化され...
[,1] [,2] [,3] [,4] # 実は R では配列は特殊...
[1,] 1 25 81 169
[2,] 4 36 100 196
[3,] 9 49 121 225
[4,] 16 64 144 256
> choose(10, 0:10) # 二項係数もベクトル化されている!
[1] 1 10 45 120 210 252 210 120 45 10 1
> choose(10:13, 10)
[1] 1 11 66 286
> choose(10:13, 0:10) # はてこれは何を計算してくれたの...
[1] 1 11 66 286 210 462 924 1716 45 55 ...
> runif(10)>0.5 # 論理判断もベクトル化され...
[1] TRUE TRUE TRUE FALSE FALSE FALSE TRUE FALSE FAL...
ベクトル化された式だけを使えば結果は自然にベクトル化され...
> foo <- function (x) sin(x>0.5) # R では論理値 TRUE, F...
> foo(runif(10))
[1] 0.000000 0.841471 0.000000 0.000000 0.841471 0.0000...
[9] 0.841471 0.841471
無理矢理ベクトル化する方法の例
> foo <- function(x) if (x<0) return(2) else return(3) ...
> foo(runif(10) - 0.5) # x の最初の要素だけ受け付ける
[1] 2
Warning message:
the condition has length > 1 and only the first element ...
...
> foo <- function (x) { # そのベクトル化版
temp <- function(x) if (x<0) return(2) e...
sapply(x, temp) } # sapply 関数は x の...
> foo(runif(10)-0.5)
[1] 2 2 2 2 3 3 3 3 2 2
> ifelse(runif(10) - 0.5 < 0, 2, 3) # 実はベクトル化さ...
[1] 3 2 2 3 3 3 3 3 2 2
> (2:3)[(runif(10) < 0.5)+1] # トリッキーな方法を追加
[1] 2 3 2 3 3 3 2 2 3 3
***引数のチェック [#j1a8a96b]
引数には自然な制約条件があることもある。そうした場合、範...
***途中の演算結果の妥当性のチェック [#m3b01d3f]
演算途中の変数値にも自然な制約範囲があることがある。もし...
***既定値つき変数の利用 [#icf88831]
幾つかの変数には容易に意味が分かる名前を付け、合理的な既...
***コードへのコメント [#oe6d4772]
他人が使う可能性のあるコードには積極的にコメントを要所要...
***複雑な関数はできるだけ細分化する [#a42626b9]
必要な機能を細分、パーツ化し小関数化する(Unix 精神)。
短い関数はチェックがし易い。また既に既成のものが存在する...
***過度の最適化は避ける [#yf48dd28]
できるだけ短くしたエレガントなコード、速度を最適化したア...
***関数は二度書く [#cc3851bf]
苦労して書いた関数は、しばしばスパゲッティコードになり、...
ページ名: