R でプログラミングする際役に立つと思われる Tips を脈絡無く集めます。なお、ある程度溜ったら適当にカテゴリー化しますので宜しく。 また、お寄せ頂いた Tips は 参照に適当と思われる場合は、合体・修正を勝手に行う場合がありますので予めご承知ください。 各自ご協力宜しく。
Rの関数定義の基本 参照
ベクトル・行列・配列・リストTips大全 を参照。
R は多くの計算機言語と同じような Algol 風制御命令のセットをもつが、より柔軟である。 実行文 expr は単純実行文でも、(波括弧で括った)複合実行文(同一行に並べるにはセミコロンで区切る)でもよい。
書式 (ループ範囲 range の各要素 arg に対して expr を実行 ) for(arg in range) expr
注意:for ループは一般に実行速度を遅くするボトルネックになりやすい。またコードが長くなり勝ちである。apply 関数ファミリの使用や、特にベクトル・行列・配列の成分ごとのループは専用高速関数が用意されているのでその使用を考える。
ループ範囲にベクトルを取る(基本) > x = 1:4 > for (i in x) cat(i,"\n") 1 2 3 4
ループ範囲に文字ベクトルを取る > x = c("a", "b", "1", "2") > for (i in x) cat(i,"\n") a b 1 2
ループ範囲に行列を取る(実際はベクトルとしてアクセス) > x = matrix(1:4, c(2,2)) > for (i in x) cat(i, "\n") 1 2 3 4
ループ範囲に配列を取る(実際はベクトルとしてアクセス) > x=array(1:8, c(2,2,2)) > for (i in x) cat(i, "\n") 1 2 3 4 5 6 7 8
ループ範囲にリストを取る > x = list("a", 1:4, 3) > for (i in x) cat(i, "\n") a 1 2 3 4 3
ループ範囲は最初に与えられたもので実行される。実行文中でループ変数を変更しても影響をうけない。 > for (i in 1:4) {i <- i+2; cat(i, "\n")} 3 4 5 6 # i=1,2,3,4 で4回実行されている
> x=1:4 > for (i in x) {x[i] <- i+10; cat(i,"\n")} 1 2 3 4 # 実行文中での範囲変数 x の変更はループ範囲を変更しない > x [1] 11 12 13 14 # x 自身は変更される
## next はループを一回パスする > for (i in 1:3) + for (j in 1:3) {if (j==2) next; cat(i, j, "\n")}} 1 1 1 3 2 1 2 3 3 1 3 3
## すべての x 中の i, j, k (i, j, k は異なる) に関する三重和 for (i in x) { for (j in x[-i]) { for (k in x[-c(i,j)]) { ..................... }}} ## または for (i in x) { for (j in x) { if (i==j) next for (k in x) { if (k==i || k==j) next ......................................... }}}
(重複の無い)数値ベクトルから長さ 3 の組み合わせをループ
> temp <- function(x){ + x <- sort(x) # ソートしておかないとまずい + for (i in x) + for (j in x[x>i]) + for (k in x[x>j]) + cat(i,j,k,"\n")} > temp(1:4) 1 2 3 1 2 4 1 3 4 2 3 4 > temp(runif(4)) 0.151133 0.223455 0.264883 0.151133 0.223455 0.993983 0.151133 0.264883 0.993983 0.223455 0.264883 0.993983
for を使わない方法,重複があってもよいし,ソートも不要
> (x <- runif(4)); t(combn(4, 3, function(i) x[i])) [1] 0.2769620 0.2577154 0.7625690 0.1760667 [,1] [,2] [,3] [1,] 0.2769620 0.2577154 0.7625690 [2,] 0.2769620 0.2577154 0.1760667 [3,] 0.2769620 0.7625690 0.1760667 [4,] 0.2577154 0.7625690 0.1760667
# condがTRUEのとき、exprを実行する。 if (cond) expr # condがFALSEのとき、alt.exprを実行する。 if (cond) cons.expr else alt.expr # if else 構文は入れ子にできる。 if (cond1) expr1 else if (cond2) expr2 else expr3 # if else 構文は値を返す。if (x < 0) y <- NA else y <- sqrt(x) と同じ。 x <- 1; y <- if (x < 0) NA else sqrt(x)
注意:ifelse(cond, expr1, expr2) 関数は if(cond) expr1 else expr2 構文を簡略化したもの
簡略化したものではない!!
> x <- -3:3 > (a <- ifelse(x < 0, NA, sqrt(x))) [1] NA NA NA 0.000000 1.000000 1.414214 1.732051 警告メッセージ: In sqrt(x) : 計算結果が NaN になりました > (b <- if(x < 0) NA else sqrt(x)) [1] NA 警告メッセージ: In if (x < 0) NA else sqrt(x) : 条件が長さが2以上なので,最初の一つだけが使われます
書式 (条件、実行文に関する注意は if 文と同様) while(cond) expr
注意:条件 cond は必ず一度は評価される
> i=0 > while( (i<-i+1) <= 5 ) cat(i, "\n") 1 2 3 4 5 > i # 実行後の i の値 [1] 6
> i = j = 0 > while( (i <- i+1) < 1 ) {j <- j+1; cat(i, "\n")} > i [1] 1 # cond は一回実行され i の値は 1 になっている > j # expr は実行されていない [1] 0
書式 (R 自身を中断しない限り、repeat 文を中断する唯一の手段は expr 中の break 文) repeat expr
書式 (プログラムの実行を中断し、これを含む制御文の次の実行文に移る) break
> i=0 > repeat {if ((i <- i+1) == 5) {cat(i,"\n"); break}} # i==5 になったら中断 5
指定秒数プログラムをアイドリングする関数(実はこのため用の関数 Sys.sleep がある -> その他の項参照) > Sleep <- function (n) { startingtime <- unclass(Sys.time()) repeat { if (unclass(Sys.time())-startingtime >= n) break } } > system.time(Sleep(20)) [1] 18.66 0.46 19.12 0.00 0.00 # 19.12 秒中断 > system.time(Sleep(10)) [1] 9.07 0.24 9.31 0.00 0.00 # 9.31 秒中断
書式 (制御文の現在の実行を中断し、次の実行サイクルに移る) next
> for (i in 1:10) {if (i%%2==0) next else cat(i,"\n")} # 偶数ならスキップ 1 3 5 7 9
書式 (EXPR は整数もしくは文字列(を与える式)) switch(EXPR, ...) 任意個数の引数 ... は選択肢リスト もし EXPR が整数値ならば該当番号の選択肢が評価され、返される もし EXPR が文字列を返すなら、それが選択肢である名前付き項目とマッチングされ、該当する項目の値が返される。 もしマッチした項目の値が欠損していれば、その次の項目の値が返される。 もしマッチする項目が一切なければ、switch にそれ以外の引数があればそれが、さもなければ NULL が返される。
> switch("cc", a=1, cc=, d=2) 2 # 項目 cc= にマッチするが値が与えられて無いので、その次の値のある項目の値 2 が返される
> switch(3, 11,12,13) [1] 13 # 3番目の数値が返される
> centre <- function(x, type) { switch(type, mean = mean(x), median = median(x), trimmed = mean(x, trim = .1)) } > x <- rcauchy(10) > centre(x, "mean") # 文字列 "mean" にマッチした項目の値 mean(x) が返される [1] -1.163613
> ccc <- c("b","QQ","a","A","bb") > for(ch in ccc) cat(ch,":",switch(EXPR = ch, a=1, b=2:3), "\n") b : 2 3 # ch="b" は項目 b=2:3 にマッチ QQ : # ch="QQ" はマッチする項目が無いので NULL が返された a : 1 A : bb : b : 2 3 > for(ch in ccc) cat(ch, ":", switch(EXPR = ch, a=, A=1, b=2:3, "Otherwise: last"), "\n") b : 2 3 QQ : Otherwise: last # マッチする名前付き項目がないので最後の文字列が返された a : 1 A : 1 bb : Otherwise: last
## EXPR が数値の時は「その他」項目は許されない > for(i in c(-1:3,9)) print(switch(i, 1,2,3,4)) NULL # i=-1 に該当する項目は無いので NULL が返された NULL [1] 1 [1] 2 [1] 3 NULL
R 関数の仮引数の数は場合により変わり得るので、ある引数が実際に存在するかどうかチェックする必要が起こる
書式 (x は関数の仮引数) missing(x)
注意:missing(x) は x が関数中で変更されると信頼できなくなる(例えば x <- match.arg() の後では必ず FALSE になる。
myplot <- function(x, y) { if(missing(y)) { y <- x # もし仮引数 y が与えられなければ y <- x とする x <- 1:length(y) } plot(x,y) }
関数の引数に与えられた値が候補のどれに一致するかどうかチェックする
書式 (choice 引数は候補リストのベクトル) match.arg(arg, choices) 部分的マッチングが行なわれるが、返り値は非省略形で与えられる。該当する項目がなければエラーメッセージがでる
center <- function(x, type = c("mean", "median", "trimmed")) { type <- match.arg(type) switch(type, # match.type の結果により switch mean = mean(x), median = median(x), trimmed = mean(x, trim = .1)) } x <- rcauchy(10) > center(x, "t") # 部分的マッチングで type="trimmed" とされた [1] 0.478473 > center(x, "med") # 部分的マッチングで type="median" とされた [1] 0.4619571 > center(x, "m") # エラー(m で始まる候補が二つある) Error in match.arg(type) : ARG should be one of mean, median, trimmed
> f <- function(x) a+b # 関数の定義 > fomrals(f) # 関数 f の形式的引数は? $x # x > formals(f) <- alist(a=, b=3) # 形式的引数 x を a ,b (b は既定値 3 付き) > f # f の定義を確認 function (a, b = 3) a + b > f(2) [1] 5 > f(2, 5) [1] 7
> f <- function() x > formals(f) <- alist(x = , y = 2, ... = ) # 「その他大勢」引数 ... の設定 > f function (x, y = 2, ...) x
> foo <- function() x # 関数を定義 > body(foo) # 関数本体を表示 x > body(foo) <- expression(x^2) # 関数本体を再定義 > foo # 確かに変わっている function () x^2
fd <- deriv(~ 100*(x2 - x1*x1)^2 + (1-x1)^2, c("x1", "x2")) # 関数の数式一階偏微分 fdd <- function(x1, x2) {} # 空の関数定義 body(fdd) <- fd # 関数の本体を fd とする
注意:これらはベクトル化されている
# 一致・大小判断は数値ベクトルのみならず R のオブジェクトにもそれぞれの意味に応じた定義がされていることがある #文字列なら辞書式順序での一致・大小判断の意味になる x == y # 一致 x != y # 不一致 x > y # x が大きい x >= y # x が大きいか等しい x < y x<= y x || y # 論理和 (x が TRUE か y が TRUE なら TRUE) x && y # 論理積 (x, y が ともに TRUE なら TRUE) !x # x の否定 x & y # ベクトルの論理積 x | y # ベクトルの論理和
> x <- (1:4)>2 > x [1] FALSE FALSE TRUE TRUE > !x [1] TRUE TRUE FALSE FALSE
> "abc" > "abd" # FALSE > "abc" > "aba" # TRUE > "abc" > "abca" # FALSE
> x <- rnorm(10) > x > 0 [1] TRUE TRUE TRUE FALSE TRUE TRUE FALSE FALSE TRUE TRUE > x[x > 0] [1] 2.0583593 0.5014932 0.8126365 0.1641549 0.6721926 0.3478276 1.6111553
注意:if 文等の検査で ==, != を使うことは避け、identical 文を使うべきである。if 文では単一の TRUE, FALSE が要求される
注意:また数値誤差の観点から実数の正確な比較は無意味になることがある
> x1 <- 0.5 - 0.3 > x2 <- 0.3 - 0.1 > x3 <- 0.4 - 0.2 > x1 == x2 # ほとんどの機械で FALSE になる > x1 == x3 # (私の機械では) TRUE > identical(all.equal(x1, x2), TRUE) # いつも TRUE
> a<-c(TRUE,FALSE,TRUE,FALSE) > b<-c(TRUE,TRUE,FALSE,FALSE) > a & b [1] TRUE FALSE FALSE FALSE > a | b [1] TRUE TRUE TRUE FALSE
二つの R オブジェクトが完全に一致するかどうかを検査する安全で信頼できる方法。
注意:通常の一致検査 x==y, x != y はしばしば困難をもたらす。x,y が異なったタイプである場合や、長さが異なる場合等。また返り値がベクトルになる可能性がある。
# 書式 identical(x, y) # x, y は二つの R オブジェクト
> if(identical(all.equal(x,y),TRUE) # R お勧めの二つのオブジェクトの一致検査 > if (x == y) # 好ましくない一致検査
> identical(1, 1.) ## R では 1 と 1. はともに倍精度実数で表現 [1] TRUE > identical(1, as.integer(1)) ## as.integer(1) は整数型なので FALSE になる [1] FALSE > x <- 1.0; y <- 0.99999999999 > identical(all.equal(x, y), TRUE) # 安全な一致比較法 [1] TRUE > all.equal(options(), .Options) [1] "Modes: list, pairlist" # 一致しないので食い違いが表示される
すべてが TRUE なら TRUE 書式 all(x) x は論理値ベクトルもしくはそれを与える式 range(x <- sort(round(rnorm(10) - 1.2,1))) if(all(x < 0)) cat("all x values are negative\n")
二つの R オブジェクトが「殆んど等しいか」どうかをチェックする。「殆んど等しい」の意味はオブジェクトにより異なる。数値ベクトルでは誤差の範囲無いで一致するかどうかを判断する。
書式 (all.equal.numeric は数値オブジェクトに対する all.equal のメソッド) all.equal(target, current, ...) all.equal.numeric(target, current, tolerance= .Machine$double.eps ^ 0.5, scale=NULL, ...) tolerance は誤差範囲の指定パラメータ
# R で階乗 n! を計算する基礎は gamma(n+1) として計算することであるが、 # gamma(n+1) の値は内部的に実数計算されるので、真の意味で n! に一致しないことを注意する > all.equal(gamma(2:14), cumprod(1:13)) # 既定の誤差範囲無いで TRUE [1] TRUE > all (gamma(2:14) == cumprod(1:13)) # 真の一致は無いので FALSE [1] FALSE > all.equal(gamma(2:14), cumprod(1:13), tol=0) # 食い違いを見る [1] "Mean relative difference: 5.198216e-15" > all.equal(options(), .Options) [1] "Modes: list, pairlist"
## 以下を比較せよ > all.equal(1, c(a=1)) # c(a=1) は名前属性付きの数値 1 [1] TRUE > identical(1, c(a=1)) [1] FALSE > attr.all.equal(1, c(a=1)) [1] "names for current but not for target" > 1 == c(a=1) a TRUE
どれかが TRUE なら TRUE 書式 any(x) x は論理値ベクトルもしくはそれを与える式 range(x <- sort(round(rnorm(10) - 1.2,1))) if(any(x < 0)) cat("x contains negative values\n")
# 書式 stopifnot(A, B, ...) # A, B, ... は真偽値を持つ任意個数のオブジェクト # A, B, ... のどれかが FALSE なら最初の FALSE となった項目を表示して stop する
> stopifnot(1 == 1, all.equal(pi, 3.14159265), 1 < 2) # すべてが TRUE なので stop しない > m <- matrix(c(1,3,3,1), 2,2) > stopifnot(m == t(m), diag(m) == rep(1,2)) # すべてが TRUE なので stop しない > stopifnot(1==1, 2< 2) Error: 2 < 2 is not TRUE # stop した > stopifnot(1:4==c(1,2,3,5)) # stop した Error: 1:4 == c(1, 2, 3, 5) is not TRUE > stopifnot(1:4==c(1,2,3,4)) # stop 無し
文字ベクトルや数値を用いてあるオブジェクト名をプログラム中で生成し、値を付値する には
> assign(paste("file", 1, "max", sep=""), 1) > ls() [1] "file1max"
変数 var1,var2,...,var10 を生成し、それぞれ値 1,2,...,10 を代入
for (i in 1:10) assign(paste("var", i, sep=""), i)
file[1],...,file[10] はデータファイル名の文字列であるとして、次の 関数はそれを読み込み、順に f1,f2,...,f10 という名前のオブジェトに付値
temp <- function() { for (i in 1:10) { assign(paste("f",i,sep=""), read.table(file[i],skip=1)) } }
順に通し番号付きの名前 d1, d2, d3 の変数を作り、それに値 x1-x2, y1-y2, z1-z2 の値を代入 (r-help 記事より、2004.09.23)
x1 <- rnorm(10); x2 <- rnorm(10) y1 <- rnorm(10); y2 <- rnorm(10) z1 <- rnorm(10); z2 <- rnorm(10) names. <- c("x", "y", "z") # 文字ベクトル for(i in names.){ # (順に)変数 x1, y1, z1 の値を res1 に代入 res1 <- get(paste(i,"1",sep="")) # (順に)変数 x2, y2, z2 の値を res2 に代入 res2 <- get(paste(i,"2",sep="")) # (順に)変数 d1, d2, d3 を作り、それに値 res1-res2 を代入 assign(paste("d",i,sep=""), res1-res2) }
> date() [1] "Fri Mar 21 15:25:05 2003" > Sys.time() [1] "2003-03-21 15:25:12 JST" > unclass(Sys.time()) [1] 1048227920 # この数値は1970年元旦(Unix 元年)からの経過
論理値ベクトル test に対し ifelse(test, x, y) は test[i]==TRUE なら x[i], test[i]==FLASE なら y[i] を並べた test と同じ長さのベクトルを返す。関数の値を変数値に応じて変えるために便利。
> x <- (-1):3 > ifelse(x>0, log(x), NA) # x <=0 なら NA を返 [1] NA NA 0.0000000 0.6931472 1.0986123 Warning message: # 途中で log(x) を計算するので NaN が発生、警告がでる NaNs produced in: log(x) > log(ifelse(x>0,x,NA)) # x=-1,0 では 先ず x <- NA となり、ついで log(NA)=NA
が返される
[1] NA NA 0.0000000 0.6931472 1.0986123 # 警告無し > ifelse(x>=0, x, -x) # abs(x) と同じ [1] 1 0 1 2 3
apply 関数ファミリーは一つの関数を複数のオブジェクトに適用して得られた結果をベクトル、行列、リストの形で一括して返す。for ループを陽に使ったり、複数オブジェクトを個別に与える必要がなく、コードが簡潔になる。また関数中で使用すれば、 R 関数プログランミングの基本精神「意味がある時は(ない時も)常にベクトル化せよ」を簡単に実現できる。
> x <- matrix(1:12, ncol=3) > x [,1] [,2] [,3] [1,] 1 5 9 [2,] 2 6 10 [3,] 3 7 11 [4,] 4 8 12 > apply(x,1,max) # 各行の最大値を求める [1] 9 10 11 12 > apply(x,2,max) # 各列の最大値を求める [1] 4 8 12
# 例 (行列の各列毎に正規化) # apply(x, 2, mean), apply(x, 2, sd) で行列 x の列毎の平均、標準偏差からなるベクトルをつくる。 # scale(x, a, b) は行列 x の第 i 列から a[i] を引き、b[i] で割った結果を表す x と同じサイズの行列を計算する。 # つまり xx[i,j] = ( x[i,j] - a[j] ) / b[j] > x <- matrix(runif(100), c(20,5)) > xx <- scale(x, apply(x, 2, mean), apply(x, 2, sd)) # チェック > apply(xx, 2, mean) # 数値誤差範囲内で各列の平均零 [1] -1.554312e-16 5.551115e-17 -1.915135e-16 1.387779e-16 -1.609823e-16 > apply(xx, 2, sd) # 標準偏差はすべて零 [1] 1 1 1 1 1 # scale 関数は列毎の操作専用なので、行毎に正規化したければまず転置しておいてから、 # 最後にまた転置する。 > xx <- t( scale(t(x), apply(t(x), 2, mean), apply(t(x), 2, sd)) )
関数 FUN を任意(個数)引数 ... 中の値を順に引数にとって得られるベクトルのリストを返す
# ベクトル rep(1,4), rep(2,3), rep(3,2), rep(4,1) を並べたリストを返す > mapply(rep, 1:4, 4:1) [[1]] [1] 1 1 1 1 [[2]] [1] 2 2 2 [[3]] [1] 3 3 [[4]] [1] 4
# rep(4,1), rep(3,2), rep(2,3), rep(1,4) を並べたリストを返す > mapply(rep, times = 1:4, x = 4:1) [[1]] [1] 4 [[2]] [1] 3 3 [[3]] [1] 2 2 2 [[4]] [1] 1 1 1 1
# rep(42, 1), rep(42, 2), rep(42,3), rep(42,4) を並べたリストを返す > mapply(rep, 42, 1:4) [[1]] [1] 42 [[2]] [1] 42 42 [[3]] [1] 42 42 42 [[4]] [1] 42 42 42 42 # mapply(rep, 1:4, 42) はすべての行ベクトルが 1:4 であるサイズ 42x4 の行列になる
> x <- matrix(1:10, byrow = TRUE, nrow = 2) > x [,1] [,2] [,3] [,4] [,5] [1,] 1 2 3 4 5 [2,] 6 7 8 9 10 > mapply(function(x1, x2) x1+x2, x[1, ], x[2, ]) # 列和 [1] 7 9 11 13 15 > mapply(function(x1, x2) x1-x2, x[1, ], x[2, ]) # 列差 [1] -5 -5 -5 -5 -5
# リストの三つの成分の平均値からなるリストを計算(論理値は整数 1,0 と見做される) > x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE, FALSE, FALSE, TRUE)) > lapply(x, mean) $a [1] 5.5 $beta [1] 4.535125 $logic [1] 0.5 > lapply(x, quantile, probs = 1:3/4) $a 25% 50% 75% 3.25 5.50 7.75 $beta 25% 50% 75% 0.2516074 1.0000000 5.0536690 $logic 25% 50% 75% 0.0 0.5 1.0
# x の中央値を計算(結果は行列の形になる) > sapply(x, quantile) a beta logic 0% 1.00 0.04978707 0.0 25% 3.25 0.25160736 0.0 50% 5.50 1.00000000 0.5 75% 7.75 5.05366896 1.0 100% 10.00 20.08553692 1.0
# 数列からなるリストの各成分の5数要約からなる行列を計算 > str(i39 <- sapply(3:9, seq)) List of 7 $ : int [1:3] 1 2 3 $ : int [1:4] 1 2 3 4 $ : int [1:5] 1 2 3 4 5 $ : int [1:6] 1 2 3 4 5 6 $ : int [1:7] 1 2 3 4 5 6 7 $ : int [1:8] 1 2 3 4 5 6 7 8 $ : int [1:9] 1 2 3 4 5 6 7 8 9 > sapply(i39, fivenum) [,1] [,2] [,3] [,4] [,5] [,6] [,7] [1,] 1.0 1.0 1 1.0 1.0 1.0 1 [2,] 1.5 1.5 2 2.0 2.5 2.5 3 [3,] 2.0 2.5 3 3.5 4.0 4.5 5 [4,] 2.5 3.5 4 5.0 5.5 6.5 7 [5,] 3.0 4.0 5 6.0 7.0 8.0 9
> n <- 17 > fac <- factor(rep(1:3, len = n), levels = 1:5) > fac [1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 # 17個のデータに与えた因子値 Levels: 1 2 3 4 5 # 因子水準は5とする > table(fac) # table 関数で因子水準毎に度数を集計 fac 1 2 3 4 5 # 数列 1:17 中の因子値が 1,2,3,4,5 であるものの度数はそれぞれ 6.6.5.0.0 6 6 5 0 0 > tapply(1:n, fac, sum) # 結果を(ラベル付き)ベクトルで返す 1 2 3 4 5 # 因子値が 1,2,3 であるグループの総和はそれぞれ 51,57,45 51 57 45 NA NA # 因子値が 4,5 のグループは空なので値 NA が返される > tapply(1:n, fac, sum, simplify = FALSE) # 結果をリストで返す $"1" [1] 51 $"2" [1] 57 $"3" [1] 45 $"4" NULL $"5" NULL > tapply(1:n, fac, prod) # 積の場合 1 2 3 4 5 58240 209440 29160 NA NA
配列の外積、クロネッカー積 を参照
R における他の関数と同様にここで紹介する関数はベクトル化されており、引数は数値・整数ベクトルが可能で、結果も対応するベクトルになる。
x + y | |
x - y | |
x * y | |
x / y | |
x ^ y | 1^y, y^0 は常に 1 になる。x,y が 正負の inf の時も可能なら合理的な値が返る |
x %% y | x mod y |
x %/% y | いわゆる整数商で値は整数。関係 x = (x%/%y)*y + x %%y が成立 |
注意:x%%y は適当な整数 n で 0<= x - ny < y となる時の値 x - ny を表す。その時の整数 n が x%/%y になる。
> x [1] -1 0 1 2 3 4 5 6 7 8 9 10 11 12 > x%%5 [1] 4 0 1 2 3 4 0 1 2 3 4 0 1 # すべて 0,1,2,3,4 の範囲の値 > x%/%5 [1] -1 0 0 0 0 0 1 1 1 1 1 2 2 2 > (x%/%5)*5+(x%%5) [1] -1 0 1 2 3 4 5 6 7 8 9 10 11 12 # x を復元
> x=1+0.5i; y= 3+2i > c(x+y, x-y, x*y, x/y, x^y) # 複素数も問題無し [1] 4.000000000000000000+2.50000000000000000i [2] -2.000000000000000000-1.50000000000000000i [3] 2.000000000000000000+3.50000000000000000i [4] 0.307692307692307709-0.03846153846153846i [5] -0.023927552111312745+0.55238103053669563i > c(x%%y, x%/%y) # これはさすがに駄目 Error: unimplemented complex operation
cos(x) | |
sin(x) | |
tan(x) | |
acos(x) | arccos |
asin(x) | arcsin |
atan(x) | arctan |
atan2(y, x) | x 軸と、原点と座標 (x,y) を結ぶベクトルのなす角 |
x、y>0 なら atan2(y,x) = atan(y/x) |
cosh(x) | (exp(x) + exp(-x))/2 |
sinh(x) | (exp(x) - exp(-x))/2 |
tanh(x) | sinh(x)/cosh(x) = (exp(x) - exp(-x))/(exp(x)+exp(-x)) |
acosh(x) | cosh(x) の逆関数 |
asinh(x) | sinh(x) の逆関数 |
atanh(x) | tanh(x) の逆関数 |
注意:底 base は実数。引数 x は実数もしくは複素数
log(x, base = exp(1)) | 底 base (既定値 exp(1)) の対数 |
logb(x, base = exp(1)) | log(x, base=exp(1)) と同じに見えるが? |
log10(x) | 常用対数 log(x, base=10) |
log2(x) | 底 2 の対数 |
exp(x) | 指数関数 |
expm1(x) | x の絶対値 が1より(かなり)小さい時、exp(x)-1 をより正確に計算 |
log1p(x) | x の絶対値が1より(かなり)小さい時、log(1+x) をより正確に計算 |
x が -1 に近い時は逆により不正確 |
> log(-1) [1] NaN Warning message: NaNs produced in: log(x)
## log も exp も所詮近似計算!精度が問題になることも? > options(digits=22) # 表示桁数最大化 > log(0.001+1) [1] 0.0009995003330834232 > log1p(0.001) ## |x| が小さければ log1p の方が相対的に正確(13桁目で食い違い) [1] 0.000999500333083533 > exp(0.01)-1 [1] 0.010050167084167949 > expm1(0.01) ## |x| が小さければ expm1 の方が相対的に正確(14桁目で食い違い) [1] 0.010050167084168058 ## 複素数もOK > log(1+2i) [1] 0.80471895621705+1.10714871779409041i > exp(1+2i)
> sqrt(-1) # 負実数の平方根は存在しないので NaN が返される [1] NaN Warning message: NaNs produced in: sqrt(-1) > sqrt(-1+0i) # しかし複素数と考えれば難なく計算 [1] 0+1i
> (x <- sample(1:10)) [1] 6 7 1 9 5 2 3 10 8 4 > cumsum(x) [1] 6 13 14 23 28 30 33 43 51 55 > cumprod(x) [1] 6 42 42 378 1890 3780 11340 113400 907200 [10] 3628800 > cummin(x) [1] 6 6 1 1 1 1 1 1 1 1 > cummax(x) [1] 6 7 7 9 9 9 9 10 10 10
引数 x は非負値、次数 nu は実数(負の値の場合を含む)
もし `expon.scaled = TRUE' ならば桁溢れ、桁落ちを避けるため exp(-x) I(x;nu) もしくは exp(x) K(x;nu) を計算
参考: Abramowitz, M. and Stegun, I. A. (1972) Handbook of Mathematical Functions.
Dover, New York; Chapter 9: Bessel Functions of Integer Order.
注意:R における数値丸め処理の基本は round 関数であるが、これは IEEE 規約に基づき、いわゆる「四捨五入」とは微妙に異なる点が有るので注意が必要。詳しくは JIS,ISO式四捨五入 を参照。
> y=ceiling(1.3) > y [1] 2 > is.integer(y) # y は整数を表す数値であり、整数保管モードではないことを注意 [1] FALSE > is.numeric(y) [1] TRUE > ceiling(1.0) [1] 1 > ceiling(-1.0) [1] -1 > ceiling(-1.3) [1] -1
> floor(c(1.3, 1.0, 0, -1.1)) [1] 1 1 0 -2
> round(c(1.32, 1.5, -0.2, -1.2, -1.5)) [1] 1 2 0 -1 -2 > round(23.5) [1] 24 > round(23.52, 1) # 小数点以下第1桁で丸める(i.e. digits =1) [1] 23.5 > round(23.52, -1) # 小数点以上第1桁で丸める [1] 20 > round(c(23.5, 24.5)) # round(24.5) は 25 でないことを注意() [1] 24 24 > round(1.3-1.2i) # 複素数も受け付ける(実・虚部をそれぞれ丸める?) [1] 1-1i
> x2 <- pi * 100^(-1:3) > round(x2, 3) [1] 0.031 3.142 314.159 31415.927 3141592.654 > signif(x2, 3) # 有効数字3桁になる [1] 3.14e-02 3.14e+00 3.14e+02 3.14e+04 3.14e+06
> trunc(c(1.2, 3, 3.1, -0.2, -0.3, -0.31, -1.3)) [1] 1 3 3 0 0 0 -1 > trunc(c(0.2, -0.2)) # 「一番近い整数」に変換 [1] 0 0 > trunc((-10):10/3) [1] -3 -3 -2 -2 -2 -1 -1 -1 0 0 0 0 0 1 1 1 2 2 2 3 3
> x2 <- pi * 100^(-1:3) > x2/1000 [1] 3.141593e-05 3.141593e-03 3.141593e-01 3.141593e+01 3.141593e+03 > zapsmall(x2/1000, digits = 4) [1] 0.0 0.0 0.3 31.4 3141.6 > round(x2/1000, digits = 4) [1] 0.0000 0.0031 0.3142 31.4159 3141.5927 > zapsmall(exp((0+1i) * 0:4 * pi/2)) # 複素数も可 [1] 1+0i 0+1i -1+0i 0-1i 1+0i
x, y 等は(同一モードの)ベクトルで、重複は無いとする。もし重複があっても、union, intersect, setdiff は重複の無い結果を返す。
union(x, y) | 和集合 |
intersect(x, y) | 積集合、共通部分 |
setdiff(x, y) | 差集合 |
setequal(x, y) | 集合として等しいか? |
is.element(el, set) | el は set に含まれるか? |
%in% | el %in% set は is.element(el, set) の簡易形 |
unique | 重複のある集合から重複元を除いて一意化する |
> (x <- c(sort(sample(1:20, 9)), NA)) [1] 1 2 5 10 12 15 17 19 20 NA > (y <- c(sort(sample(3:23, 7)), NA)) [1] 4 5 6 9 13 14 16 NA > union(x, y) # 和集合 [1] 1 2 5 10 12 15 17 19 20 NA 4 6 9 13 14 16 > intersect(x, y) # 共通集合 [1] 5 NA > setdiff(x, y) # 差集合(x の要素の内、y に属さないものの全体) [1] 1 2 10 12 15 17 19 20 > setdiff(y, x) [1] 4 6 9 13 14 16
> setequal(x, y) # 集合としての同等性検査 [1] FALSE > setequal(1:3, 3:1) [1] TRUE # 集合としては等しい! > is.element(x, y) # x の各要素毎に y に所属するかどうか検査 [1] FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE > y %in% x [1] FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE
> x <- unique(c(1:5, 3:7, 8:2)) [1] 1 2 3 4 5 6 7 8 # 重複要素を一意化
ソート、オーダー、ランク を参照
max(..., na.rm=FALSE) min(..., na.rm=FALSE)
pmax(..., na.rm=FALSE) pmin(..., na.rm=FALSE)
range(..., na.rm = FALSE) range.default(..., na.rm = FALSE, finite = FALSE)
mean(x, ...) mean.default(x, trim = 0, na.rm = FALSE, ...) weighted.mean
> ave(1:5) # グルーピング変数無し。x[1],...,x[5] 毎に mean(1:5) が返される [1] 3 3 3 3 3 > ave(1:3, factor(c(1,1,2))) # y[1]=y[2]=(x[1]+x[2])/2, y[3]=x[3] [1] 1.5 1.5 3.0 > ave(1:3, factor(c(1,2,2))) # y[1]=x[1], y[2]=y[3]=(x[2]+x[3])/2 [1] 1.0 2.5 2.5 > ave(1:3, factor(c(1,2,2)), FUN=max) # y[1]=max(x[1]), y[2]=y[3]=max(x[2],x[3]) [1] 1 3 3
> data(warpbreaks); attach(warpbreaks) > warpbreaks breaks wool tension 1 26 A L 2 30 A L 3 54 A L --- 途中省略 --- 53 16 B H 54 28 B H > wool [1] A A A A A A A A A A A A A A A A A A A A A A A A A A A B B B B B B B B B B B [39] B B B B B B B B B B B B B B B B Levels: A B > ave(breaks, wool) # wool の種類 A, B 毎の平均 [1] 31.03704 31.03704 31.03704 31.03704 31.03704 31.03704 31.03704 31.03704 [9] 31.03704 31.03704 31.03704 31.03704 31.03704 31.03704 31.03704 31.03704 [17] 31.03704 31.03704 31.03704 31.03704 31.03704 31.03704 31.03704 31.03704 [25] 31.03704 31.03704 31.03704 25.25926 25.25926 25.25926 25.25926 25.25926 [33] 25.25926 25.25926 25.25926 25.25926 25.25926 25.25926 25.25926 25.25926 [41] 25.25926 25.25926 25.25926 25.25926 25.25926 25.25926 25.25926 25.25926 [49] 25.25926 25.25926 25.25926 25.25926 25.25926 25.25926 > unique(ave(breaks, wool)) [1] 31.03704 25.25926 # A, B に対する二種類の平均
median(x, na.rm=FALSE) quantile(x, probs = seq(0, 1, 0.25), na.rm = FALSE, names = TRUE, ...) fivenum(x, na.rm = TRUE) IQR
mad cumsum colSUms
var(x, y = NULL, na.rm = FALSE, use) cor(x, y = NULL, use = "all.obs") cov(x, y = NULL, use = "all.obs") sd(x, na.rm = FALSE) cov.mt
diff(x, ...) diff.default(x, lag=1, differences=1, ...)
String2Eval を R のオブジェクト・命令を表す文字列とすると eval(parse(text = String2Eval)) はそれを解釈実行する
> eval(parse(text="ls()")) > eval(parse(text = "x[3] <- 5"))
> hoge <- function(a, b) { x1 <- paste("temp <- function(x) {",sep="") # 関数 temp を表現する文字列の一部 x2 <- paste("a*x + b} ",sep="") # 関数 temp を表現する文字列の一部 eval(parse(text=paste(x1,x2,sep=""))) # 関数 temp(x) を定義 temp(9) } # temp(9) を即座に実行する > hoge(1,2) # 内部で関数 temp(x) が定義され、temp(9) を計算する [1] 11 # 以下でも同じこと > hoge <- function(a, b) { x1 <- paste("temp <- function(x) {",sep="") x2 <- paste(a, "*x + ", b, "} ",sep="") eval(parse(text=paste(x1,x2,sep=""))) temp(9) } # 匿名関数を利用する例 hoge <- function(a, b) { x1 <- paste("(function(x) { ", sep="") # 関数 temp を表現する文字列の一部 x2 <- paste("a*x + b} )(9)", sep="") # 関数 temp を表現する文字列の一部 y <- eval(parse(text=paste(x1,x2,sep=""))) # 関数 temp(x) を定義 y } hoge(1,2) [1] 11 # 内部で定義された関数は hoge 終了時には消える。hoge を呼び出した環境中に定義するには次のようにする # (temp(x) は hoge 中でも実行可能) > rm(temp) > hoge <- function(a, b) { x1 <- paste("temp <- function(x) {",sep="") x2 <- paste(a, "*x + ", b, "} ",sep="") eval.parent(parse(text=paste(x1,x2,sep=""), n=1)) } > hoge(1,2) > temp # 関数 temp(x) が定義されて(残って)いる function(x) {1*x + 2} # 応用問題。通し番号つきの関数をプログラム中で作成 > hoge <- function(a, b) { # a,b は共通パラメータ for (i in 1:3) { code <- paste("temp", i, " <- function(x) ", a, "*x^(", i, ")+ ", b, sep="") eval.parent(parse(text=code), n=1) } } > hoge(1,2) > temp1 function(x) 1*x^(1)+ 2 > temp2 function(x) 1*x^(2)+ 2 > temp3 function(x) 1*x^(3)+ 2
> xyz <- 1:5 > get("xyz") [1] 1 2 3 4 5 > eval(parse(text="xyz")) # これでも良い [1] 1 2 3 4 5 > foo <- function(x) x^2 > get("foo") function(x) x^2 > eval(parse(text="foo")) # これでも良い function(x) x^2
一つの関数から複数の値を返すにはベクトル、配列等のオブジェクトを返り値とすれば良い。return 関数に複数の引数を与えると、それらは自動的にリストとして返される。リストの各成分には元の変数名が名前タグとして自動的に付加される。
注意:この機能は将来は廃止の予定、R 1.8 からは警告が出る。) 代わりに返り値として明示的にリストを与える。
> test <- function(x){y=log(x);z=sin(x);return(x,y,z)} > test(1:3) $x [1] 1 2 3 $y [1] 0.0000000 0.6931472 1.0986123 $z [1] 0.8414710 0.9092974 0.1411200
名前タグを自前で指定するには明示的に名前付きリストを返り値にする
> test <- function(x){y=log(x);z=sin(x);return(list(value=x,log=y,sin=z))} > test(1:3) $value [1] 1 2 3 $log [1] 0.0000000 0.6931472 1.0986123 $sin [1] 0.8414710 0.9092974 0.1411200
R の関数内部には別の関数定義を置き、その場で実行できる
"test" <- function() { "hello" <- # 関数内部での関数定義 function() { x <- 1:3 y <- 23:34 z <- cbind(x,y) return(x,y,z) } c <- hello() # その実行 return(c$z,c$x, c$y) }
永続付値演算子は現在の環境の親R環境中のオブジェクトに対する操作であり、特に関数中で用いるときは注意がいる。永続付値演算子を関数中で用いるとき陥りやす間違いは次の例でみられる:
> v <- 1 > test <- function () {v <- 2; v <<- 3; cat("v=",v,"\n")} > test() v= 2 > v [1] 3
この例では関数内部での変数 v と永続付値で生成された親環境(つまり関数 test を 実行した環境)中の変数 v という、同じ名前だが実体が異なる二つの変数が登場する。関数中では単なる変数 v は局所的な変数を指し、関数実行後は残らない。一方変数v は関数実行後も残る
#もう少し微妙な例: > test <- function () {v <- 1:3; v[2] <<- 0; cat("v=",v,"\n")} > test() v= 1 2 3 # 局所的な v の値 > v [1] 1 0 3 # 大局的な v の値(いつの間にかベクトルになっていることに注意)
教訓: 永続付値は便利だが使用には注意がいる。使うときはできるだけ個性的な名前 を用いる。決して親環境(場合によるとそのまた親環境等)、もしくは関数中の局所的変数と紛らわしい名前は使わない!
特に R の大局的環境(起動時の環境)は .GlobalEnv という名前が与えられている。大局的環境中のオブジェクトは任意の関数から直ちに参照でき、特に副関数に複雑な引数を(参照渡し、コピー無し)引き渡すとき便利である。大局的環境中の変数の操作には明示的に assign 関数を用いるのが安全な方法。
assign(x, 2, env=.GlobalEnv) # 大局的環境中の変数 x に値 2 を代入
多くの場合これは x <<- 2 と同等の効果を持つが、環境が何重にも入れ子になっている場合は致命的なエラーを(気づかぬままに)侵す可能性がある。
永続付値の項で述べた同じ名前でも環境(簡単にいえばメモリースペース)が異なれば違 た実体を持つという点は次の積極的に仮の環境を使う例で一層はっきりする。多少面倒だが多数の関共有する変数はこうした一次的作業環境に置いておくと混乱が無いかも知れない。またこれは R でオブジェクトのコピー無しで他から参照する(参照渡し)を実現する手段でもある。
> rm(v) # 大局的環境に変数 v があれば抹消 > tempenv <- new.env(TRUE,NULL) # 新しい環境を作り tempenv と名付ける > assign("v",3,env=tempenv) # 環境 tempenv 中に変数 v (注意:文字列で与える)を作り、値を 3 とする > v Error: Object "v" not found # 大局的環境には v という変数は無いのでエラー > ls(envir=tempenv) # 環境 tempenv 中の変数一覧 [1] "v" # v という変数がある! > get("v",env=tempenv) # 環境 tempenv 中の変数 v の値を得る [1] 3 > rm(tempenv) # 環境 tempenv は大局的環境 .GlobalEnv 中のオブジェクト、rm 関数で抹消できる > ls(envir=tempenv) Error in ls(envir = tempenv) : Object "tempenv" not found
キー入力があるまでプログラム、プロットの実行を停止。指定メッセージを出力し 何かをキー入力したら以下を実行
> temp <- function(x) { cat("sum of x is -->", sum(x), "\n") readline("Can I proceed? ") cat("prod of x is -->", prod(x),"\n") } > temp(1:4) sum of x is --> 10 Can I proceed? #ここで何かをキー入力すると次を実行 prod of x is --> 24
これは example 関数によるデモを実行する際、ひき続くグラフィックス表示を 一つずつ眺めるためにも有効である。par(ask=FALSE) を実行すれば元に戻る
> a [1] 0.557755694 0.756125389 0.062838319 0.116221907 0.287878570 0.490844365 [7] 0.988744111 0.681430858 0.681793307 0.008137233 > y <- readline() a > y # y は文字列でそのままではオブジェクト名ではない [1] "a" > eval(parse(text=y)) # 文字列 y をオブジェクト名 a に変換し評価した [1] 0.557755694 0.756125389 0.062838319 0.116221907 0.287878570 0.490844365 [7] 0.988744111 0.681430858 0.681793307 0.008137233 > get(y) # 同じこと。get 関数は文字列を与え、対応するオブジェクトの値を返す [1] 0.557755694 0.756125389 0.062838319 0.116221907 0.287878570 0.490844365 [7] 0.988744111 0.681430858 0.681793307 0.008137233
readline 関数による入力は文字列となるので、数値を入力するにはひと工夫がいる。
> x <- readline() 1.2 # 1.2 を入力 > x [1] "1.2" # 文字列になっている > xx <- as.numeric(x) # 数値に強制変換 > xx [1] 1.2
もし複数の数値をいっぺんに入力したければ次のようにします。つまり readline 関数で読み込んだ複数数値を表す文字列(半角空白一つを間にはさむ)を、strsplit 関数で文字列リストに変換、unlist 関数で文字列ベクトルに変え、最後に as.numeric で数値に強制変換します。
> x <- as.numeric(unlist(strsplit(readline(), split=" "))) 1.0 2 -3.9 > x [1] 1.0 2.0 -3.9
もし入力に複数の半角空白が分離記号として入っていれば正規表現 :space:+ (半角空白の一個以上の繰返し)を split オプションに指定。
> x <- readline() 2 3 1.14 > x [1] "2 3 1.14" # 入力先頭の半角空白は無視される > xx <- as.numeric(unlist(strsplit(x,split="[[:space:]]+"))) > xx [1] 2.00 3.00 1.14 # 整数 2,3 が欲しければすこし厄介(後から as.integer 関数を使う?)
関数の定義をテキストファイル(例えば "myfun.R")に書き source("myfun.R") 関数で 読み込むR の初期設定ファイル .Rprofile に行 source("myfun.R") を入れておけばいつも自動に読み込まれる)
R セッション中に関数定義を save() 関数で Rdata ファイルに保存しておく。関数
attach() で定義ファイルを読み込むことができる
> myfun <- function(x) cat(x,"\n") > save(myfun, file="myfun.Rdata") .......... 次の R セッション............ > attach("myfun.Rdata")
readline 関数で指定プロンプトを提示し、対話的に文字列を入力(任意の分離記号を指定 できる)結果 Str は文字列 "10,20,30"。strsplit 関数で文字列リストに変換し、unlist 関数で文字列ベクトル化 as.numeric 関数で数値化する
> Str <- readline("Enter x: ") Enter x: 10,20,30 # プロンプトと、入力数値 > x <- as.numeric(unlist(strsplit(Str, ","))) # Str は文字ベクトル > x [1] 10 20 30 # x は数値ベクトル c(10,20,30)
R からファイルを操作するには完全なディレクトリを込めて指定するのが一番安全。 現在のディレクトリを R から変更することもできる。但し R から(Unix の)OS命令を実行する基本である system("命令名")は必ずしも希望の結果を得られないこともあるらしい。
> getwd() # 現在のディレクトリを表 [1] "/home/hoge" > system("cd ..") # Unix 命令 "cd .." を実行 > getwd() [1] "/home/hoge" # しかし実際は変更はされて > getwd() [1] "/home/hoge/" > setwd("..") > getwd() [1] "/home" # 変更されている > setwd("~") > getwd() [1] "/home/hoge"
以下で ..., file1,file2, to, from はファイル名を表す文字列(ベクトル)。path は単一のパス名を含む文字ベクトル。overwrite は論理値でファイルを上書きするかどうかを指示する。
The '...' arguments are concatenated to form one character string: you can specify the files separately or as one vector. All of these functions expand path names: see 'path.expand'.
'file.create' creates files with the given names if they do not already exist and truncates them if they do.
'file.exists' returns a logical vector indicating whether the files named by its argument exist.
'file.remove' attempts to remove the files named in its argument.
'file.rename' attempts to rename a single file.
'file.append' attempts to append the files named by its second argument to those named by its first. The R subscript recycling rule is used to align names given in vectors of different lengths.
'file.copy' works in a similar way to 'file.append' but with the arguments in the natural order for copying. Copying to existing destination files is skipped unless 'overwrite = TRUE'. The 'to' argument can specify a single existing directory.
'file.symlink' makes symbolic links on those Unix-like platforms which support them. The 'to' argument can specify a single existing directory.
'dir.create' creates the last element of the path.
Value:
'dir.create' and 'file.rename' return a logical, true for success.
The remaining functions return a logical vector indicating which operation succeeded for each of the files attempted.
Author(s):
Ross Ihaka, Brian Ripley
See Also:
'file.info', 'file.access', 'file.path', 'file.show', 'list.files', 'unlink', 'basename', 'path.expand'.
cat("file A\n", file="A") cat("file B\n", file="B") file.append("A", "B") file.create("A") file.append("A", rep("B", 10)) if(interactive()) file.show("A") file.copy("A", "C") dir.create("tmp") file.copy(c("A", "B"), "tmp") list.files("tmp") setwd("tmp") file.remove("B") file.symlink(file.path("..", c("A", "B")), ".") setwd("..") unlink("tmp", recursive=TRUE) file.remove("A", "B", "C")
R コード中の # はそれ以降行末までをコメントとみなし無視する(日本語もOK) コード中の各行は先頭に # をつければ注釈できるが、長い行をひとかたまりに 注釈化するには次の構文で囲む。つまり if 文の条件が常に FALSE だから括弧内はすべ て無視される
if(0) {(長い行........)}
応用:foo(x, 1) ならデバッグ用コードを実行、foo(x) ならしない foo <- function(x, debug=0) { # 既定ではデバッグ用コードを実行しない ............................................ if(debug==1) { ... デバッグ用コード ... } .............................................. }
シミュレーション等でエラーが起こる可能性のある場合、続けて次のシミュレーションを続行するのに便利。
#書式 try(expr, silent = FALSE, first = TRUE) # expr は実行可能な表現 # silent =TRUE ならエラーコードを表示しない
## シミュレーションを100回実行、エラーにならなかった場合の結果を記録 set.seed(123) # 結果を再現できるように乱数種を指定 x <- rnorm(50) # 正規乱数50個 doit <- function(x) # シミュレーションコード { x <- sample(x, replace=TRUE) # x から重複を許して(x と同じ数だけ)無作為抽出 if(length(unique(x)) > 30) mean(x) # 重複を除いて 31 個以上なら平均計算 else stop("too few unique points") # さもなければ中断 } ## doit を100回実行し、結果をリスト res に連続記録 res <- lapply(1:100, function(i) try(doit(x), TRUE)) res [[1]] # 1回目は失敗 [1] "Error in doit(x) : too few unique points\n" attr(,"class") [1] "try-error" [[2]] #2回目は成功 [1] 0.1529146 [[3]] # 3回目は失敗 [1] "Error in doit(x) : too few unique points\n" attr(,"class") [1] "try-error" [[4]] # 4回目は成功 [1] 0.08090636 ------- 途中省略 ------------------------ [[100]] [1] 0.04618465 > unlist(res) # 非リスト化(文字列ベクトルになる) [1] "Error in doit(x) : too few unique points\n" [2] "0.152914625907379" [3] "Error in doit(x) : too few unique points\n" [4] "0.0809063649112537" ------- 途中省略 ------ [99] "-0.0810531720129378" [100] "0.0461846522112245"
> x=1:4 # 付値のみで結果の表示はない > (x=1:4) # 丸括弧で囲むと、付値した結果を表示 [1] 1 2 3 4 > test1(x) <- function() y <- 2*x > test1(1:4) # 何も表示されない > test2 <- function(x) (y <- 2*x) > test2(1:4) # 丸括弧で囲むと付値した上で表示される [1] 2 4 6 8
## 選択肢番号により switch 文で実行内容を変える > switch(menu(c("A","B"), title="My Menu (0 for no selection)") + 1, cat("Nothing is chosen\n"), cat("A is chosen\n"), cat("B is chosen\n")) My Menu (0 for no selection) 1:A 2:B Selection: 1 A is chosen > switch(menu(c("A","B"), title="My Menu") + 1, cat("Nothing is chosen\n"), cat("A is chosen\n"), cat("B is chosen\n")) My Menu (0 for no selection) 1:A 2:B Selection: A A is chosen > switch(menu(c("A","B"), title="My Menu") + 1, cat("Nothing is chosen\n"), cat("A is chosen\n"), cat("B is chosen\n")) My Menu (0 for no selection) 1:A 2:B Selection: 0 Nothing is chosen
R の論理値 TRUE, FALSE は数値が必要とされる文脈では整数値 1, 0 に強制変換されるが、明示的に数値に変換するには次のようにする。
> x <- matrix(1:4, 2, 2) > x [,1] [,2] [1,] 1 3 [2,] 2 4 > xx <- x>2.5 > xx # 論理値行列 [,1] [,2] [1,] FALSE TRUE [2,] FALSE TRUE > xx+0 # 数値に強制変換 [,1] [,2] [1,] 0 1 [2,] 0 1 > xx + 0:0 # 保管モードを整数にする [,1] [,2] # 大規模行列ではメモリ使用量が減るメリット [1,] 0 1 [2,] 0 1
## storage.mode(xx) <- "integer" でも良い ## as.integer 関数では行列属性を除いてしまう > as.integer(xx) [1] 0 0 1 1
R では論理値 TRUE, FALSE は文脈に応じて整数 1,0 に強制変換されるので、表示の際気持ちが悪いということがなければ、整数として使いたい場合でも特に整数に明示的に変換する必要はない。それでも変換したければ次のようなトリックが使える。
> is.integer(TRUE+FALSE) # 足し算をすれば強制変換される [1] TRUE > is.integer(TRUE*TRUE) # かけ算をすれば強制変換される [1] TRUE > is.integer(TRUE+0:0) # 0:0 は整数 0 になるからそれを足せば整数に強制変換される [1] TRUE > is.integer(TRUE*1:1) # 1:1 は整数 1 になるからそれをかけると整数に強制変換される [1] TRUE > is.real(x+0) # 0 は実数とみなされるので結果も実数に強制変換される [1] TRUE > as.integer(c(TRUE, FALSE)) # 明示的な整数への変換例 [1] 1 0 > x = matrix(c(TRUE, FALSE, FALSE, TRUE), c(2,2)) # 論理値行列 > x [,1] [,2] [1,] TRUE FALSE [2,] FALSE TRUE > x+0:0 # 整数値行列に変換 [,1] [,2] [1,] 1 0 [2,] 0 1
> base::log # base パッケージ中の関数 log の情報を得る function (x, base = exp(1)) if (missing(base)) .Internal(log(x)) else .Internal(log(x, base)) <environment: namespace:base> > base::"+" # base パッケージ中の関数 "+" の情報を得る .Primitive("+")
もしパッケージもしくは自己定義関数中で既存の関数と同じ名前のオブジェクトを重複定義しても、ダブルコロン演算子を使えば問題ない。インストール済みのパッケージをオンデマンドでロードするにも便利。
> base::log(10) [1] 2.302585
> log <- function(x) exp(x) # log 関数の再定義 > log function(x) exp(x) > log(1) # 再定義による値 [1] 2.718282 > base::log(1) # 本来の log 関数の値が得られる [1] 0
> x = rnorm(100) > medpolish(x) # eda パッケージ中の関数 medpolish (未ロードなのでエラー) Error: couldn't find function "medpolish" > eda::medpolish(x) # eda パッケージを自動ロードするのでエラーにならない Final: 0 Median Polish Results (Dataset: "x") Overall: -0.08048712 Row Effects: [1] 0.859951758 0.055019070 1.770125505 -0.700803046 0.792711958 # 以下省略
> eda::medpolish <- function(x) {median(x)} # eda パッケージ中への代入は不可 Error: Object "eda" not found
値の分類区間を breaks ベクトルで与え、分類ラベルを labels で与える。ラベルは因子になるので、数値としてのあつかいはそのままでは不可能
> x <- 2000*runif(10) > y <- cut(x, breaks=c(-Inf, 500, 1000, 2000, Inf), labels=c(0,1,2,3)) > y [1] 2 2 2 2 2 2 2 2 1 1 Levels: 0 1 2 3 > as.integer(y) # 数値に変更 [1] 3 3 3 3 3 3 3 3 2 2 ## ラベルを FALSE にすると区間のかずに応じたラベルが数値として与えられる > y <- cut(x, breaks=c(-Inf, 500, 1000, 2000, Inf), labels=FALSE) > y # 結果は数値 0.1.2.3 [1] 3 3 3 3 3 3 3 3 2 2 ## labels 引数を省略すると該当区間を表す文字列がラベル(因子)として与えられる > y <- cut(x, breaks=c(-Inf, 500, 1000, 2000, Inf)) > y [1] (1e+03,2e+03] (1e+03,2e+03] (1e+03,2e+03] (1e+03,2e+03] (1e+03,2e+03] [6] (1e+03,2e+03] (1e+03,2e+03] (1e+03,2e+03] (500,1e+03] (500,1e+03] Levels: (-Inf,500] (500,1e+03] (1e+03,2e+03] (2e+03,Inf]
> p1 <- proc.time() # 現在の内部タイマーを得る > Sys.sleep(3.7) # 3.7 秒実行休止 > proc.time() - p1 # 経過時間を得る [1] 0.00 0.01 3.71 0.00 0.00 # 3.71 秒経過
書式:
list.files(path = ".", pattern = NULL, all.files = FALSE, full.names = FALSE, recursive = FALSE) dir(path = ".", pattern = NULL, all.files = FALSE, # list.files の別名 full.names = FALSE, recursive = FALSE)
引数:
例:
list.files(R.home()) ## 最初が文字 a-l と r (大文字を含む)だけをリストアップ(正規表現) dir("../..", pattern = "^[a-lr]", full.names=TRUE)
## 現ディレクトリ中のすべてのファイルについてある処理を行なう例 lapply(list.files(), function(x) paste('filename is ',x))
## 同じことを for ループで実現 files <- list.files() for (each.file in files){ paste('filename is ',x) }
## 正規表現によるファイル名(a3b.txt といったファイル名)のリストアップと、 ## その内容を読み込んだデータファイルをリストへ一括格納。 tab <- lapply(list.files(pattern="^?[[:digit:]]?.txt"), read.table) # 各データフレームは tab[[1]],...,tab[[4]] で得られる
structure(x, ...) はオブジェクト x に tag = value の形で任意個数の属性を付与する。
> structure(1:6, dim = 2:3) # 次元属性 dim = 2:3 を与える [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6
例えばベクトルの内容を出力する際、一行あたりの要素の数を少なくしたいことがある。 width オプションの既定値は80文字である。
> x <- runif(10) > x [1] 0.3670568 0.7209854 0.9568679 0.4202735 0.1225961 0.2212387 0.3502483 [8] 0.1798455 0.8755473 0.5800494 > options(width=30) > x [1] 0.3670568 0.7209854 # 一行の文字数が30を越えないように折り返される [3] 0.9568679 0.4202735 [5] 0.1225961 0.2212387 [7] 0.3502483 0.1798455 [9] 0.8755473 0.5800494 > options(width=50) > x [1] 0.3670568 0.7209854 0.9568679 0.4202735 [5] 0.1225961 0.2212387 0.3502483 0.1798455 [9] 0.8755473 0.5800494
Unix-like OS では system() 関数を使い、Unix 命令を実行可能なので、これらの関数がなくてもとりあえず困らない。またこれらの関数がすべての OS でうまく動くかどうか不明。 OS 依存のディレクトリ、ファイル名の困難を避けるために、list.files() 関数(少し上を参照)と併用すると安心。
file.create(...) # ファイルを新規作成 file.exists(...) # ファイルが存在するかどうかチェック file.remove(...) # ファイルを削除 file.rename(from, to) # ファイル名を変更 file.append(file1, file2) # ファイルを合併 file.copy(from, to, overwrite = FALSE) # ファイルをコピー file.symlink(from, to) # シンボリックリンク dir.create(path, showWarnings = TRUE) # 新規ディレクトリを作成
以下のような入れ子になったリストを考えてみる.
list(10, list(list(30, 20), 1:10), list(2:5))
ここで,このようなリストの末端にある数値を全て足す関数を定義してみる.このリストの個々の要素は同じ構造の(ただし入れ子が一段少ない)リストなので,個々の要素を自分自身を呼び出すことによって(再帰呼び出しによって)処理することが出来る.
# リスト x の末端にある数値の総和を求める関数 myfunc <- function(x) { if (is.atomic(x)) return(sum(x)) # リストでなければ単に和を返す s <- 0 # 変数を初期化 for (i in x) { # リストの要素それぞれについて s <- s + myfunc(i) # 末端の数値の和を計算してそれを加算していく } return(s) # 総和を返す }
次は再帰プログラムの例ではありきたりの階乗を求めるプログラムである.
myfunc <- function(n) { if (n <= 1) return(1) else n * myfunc(n-1) } myfunc(5) [1] 120 # 改良版:ベクトルの各要素ごとに階乗を求められる myfunc2 <- function(x) { recurse <- (x>1) x[!recurse] <- 1 if (any(recurse)) { y <- x[recurse] x[recurse] <- y*myfunc2(y-1) } return(x) } myfunc2(5) [1] 120 myfunc2(1:10) [1] 1 2 6 24 120 720 5040 40320 [9] 362880 3628800
Recall によって関数の名前に依存せずに再帰呼び出しを行なうことも出来る.先の例では関数名を変えると本体で自分自身を呼び出しているところも変更しなければらなかったが,Recall を使って再帰呼び出しを行なっていればその必要はなくなる.
再帰関数を用いることで,数値積分を行うことが出来る.以下は数値積分を行う関数 area(関数, 左端の点, 右端の点) である.
area <- function(f, a, b, eps = 1.0e-06, lim = 10) { fun1 <- function(f, a, b, fa, fb, a0, eps, lim, fun) { ## 関数‘fun1’ は‘area’ の中からだけ見える d <- (a + b)/2 h <- (b - a)/4 fd <- f(d) a1 <- h * (fa + fd) a2 <- h * (fd + fb) if(abs(a0 - a1 - a2) < eps || lim == 0) return(a1 + a2) else { return(fun(f, a, d, fa, fd, a1, eps, lim - 1, fun) + fun(f, d, b, fd, fb, a2, eps, lim - 1, fun)) } } fa <- f(a) fb <- f(b) a0 <- ((fa + fb) * (b - a))/2 fun1(f, a, b, fa, fb, a0, eps, lim, fun1) }
上の関数 area() を定義すると,以下のように積分計算が出来る.
area(sin,0,pi/2) [1] 0.999987