R

トップページ

Google
WWWを検索
サイト内を検索

lapply, sapply, vapply, apply, tapplyの順番に説明していきます。

1 データセットの作成

applyを試す前に、処理するデータをつくります。

df01 <- with(list(n=100), {
    x <- 1:n
    p <- runif(n)
    d <- ifelse(p<0.3, "A", ifelse(p<0.7, "B", "C"))
    z <- rnorm(n) + p
    y <- 1 + 2*x - z + rnorm(n)
    data.frame(y, x, z, d)
})

中はhead(df01)とでもして確認してください。

2 引数がベクターもしくはリスト

ベクターもしくはリストの引数を取れるsapply/lapplyは、名前からすると簡素版と言った感じですが、(ベクターに二次元構造を持たせた)行列や、(リストに各要素の長さが等しいという制約のついた)データフレームを要求するapplyよりも、構造的にはむしろ基本です。

2.1 lapply

lapplyがもっとも単純な関数で、戻り値としてリストを返してきます。

lapply(unique(df01$d), function(n){ sprintf("列名%s", n)})
[[1]]
[1] "列名C"

[[2]]
[1] "列名A"

[[3]]
[1] "列名B"

第1引数がベクターもしくはリストで、第2引数がベクターもしくはリストのそれぞれの要素を処理していく関数となります。 lapplyに渡す関数の引数が複数ある場合は、lapplyの第3引数以降に、例えば以下のように指定します。

lapply(unique(df01$d), function(n, m){ sprintf("列名%s%s", n, m)}, "です")
[[1]]
[1] "列名Cです"

[[2]]
[1] "列名Aです"

[[3]]
[1] "列名Bです"

2.2 sapply

戻り値がリストのままでは使いづらいことが多いので、ラッパー関数sapplyが用意されていて、ベクトルで結果を得ることができます。

sapply(unique(df01$d), function(n){ sprintf("列名%s", n)})
      C       A       B 
"列名C" "列名A" "列名B" 

以下のようにオプションをつけると、sapplylapplyと同じ動作になります。

sapply(unique(df01$d), function(n){ sprintf("列名%s", n)}, simplify = FALSE, USE.NAMES = TRUE)

2.3 vapply

vapplysapplyと同じ目的に使いますが、戻り値の型をチェックするところがsapplyと異なります。

sapply(df01, max) # エラーにならない
vapply(df01, max, numeric(1)) # エラーになる

利用頻度は低いようです。

3 引数が行列もしくはデータフレーム

引数が行列もしくはデータフレームのときはapply関数を用います。行ごと、もしくは列ごとに関数を用いることができます。 まずはmean関数と行列にする都合で、numeric型の列だけ選んでおきます。

df02 <- df01[,c("y", "x", "z")] 

3.1 引数がデータフレーム

第2引数が1だと行ごとの処理、2だと列ごとの処理になります。

apply(df02, 1, mean) # 行ごとに合計
  [1]  1.526211  2.113033  3.509647  4.797330  4.776226  6.461667  7.401590
  [8]  8.306299  9.496788 10.177425 11.428643 12.284588 13.166522 14.754029
 [15] 15.687962 16.338175 16.934477 18.173881 19.476747 19.859839 21.374476
 [22] 22.540851 23.285823 24.296316 25.139580 26.344595 27.062882 28.366263
 [29] 28.730967 29.849099 30.913932 32.893642 33.075588 34.205878 35.274073
 [36] 36.576408 37.372630 38.924394 39.095235 40.014075 42.026347 42.117216
 [43] 43.340190 44.713445 45.386236 46.654625 47.542863 48.068348 49.526155
 [50] 49.967447 51.432997 52.428179 53.236877 54.698340 55.510672 55.920055
 [57] 57.637786 58.568035 59.626654 59.798304 60.986118 61.871337 63.089312
 [64] 64.877271 65.180877 66.107368 67.783360 68.345286 69.183056 70.546051
 [71] 71.477012 72.563960 73.112758 74.513534 75.481333 77.338646 77.324309
 [78] 78.181357 79.363223 80.840083 81.183187 81.957013 83.219194 84.686786
 [85] 85.681126 86.480538 87.285891 88.684882 88.785926 89.960381 91.101880
 [92] 92.426905 93.137565 94.152389 96.030607 96.134188 97.558614 98.088797
 [99] 98.701107 99.573988
apply(df02, 2, mean) # 列ごとに合計
          y           x           z 
101.5146787  50.5000000   0.4814943 
apply(df02, 2, mean, simplify=FALSE) # 結果をlistにする
$y
[1] 101.5147

$x
[1] 50.5

$z
[1] 0.4814943

3.2 引数が行列

行列でもデータフレームと同様に処理できます。

X <- as.matrix(df02) # データフレームを行列にする
apply(X, 1, max) # 行ごとに最大値
  [1]   3.835356   4.644549   5.836006   9.878820   7.797525  12.022988
  [7]  13.745456  15.611779  19.138381  19.624160  26.609122  22.831101
 [13]  26.046653  30.099623  31.502021  31.054062  34.259921  37.827238
 [19]  40.377531  39.796067  42.724629  45.485327  47.356008  47.962590
 [25]  51.015225  51.238400  53.143083  58.775892  57.010789  58.912396
 [31]  61.435449  66.245301  66.026187  67.053527  70.067206  73.358105
 [37]  75.923200  77.237279  77.797615  81.050269  85.455753  84.477436
 [43]  86.350083  88.917300  91.204088  93.272812  92.026362  94.656470
 [49]  99.370288  98.097401 104.378386 104.745716 106.490581 108.761660
 [55] 111.962380 112.342535 115.894078 116.964650 118.703089 118.988275
 [61] 123.027746 121.831321 125.006410 130.286607 131.284012 131.852469
 [67] 135.910727 137.561625 138.442263 140.410763 143.260771 146.197721
 [73] 145.942253 147.726196 150.406887 155.478777 152.382639 155.871938
 [79] 157.074580 162.610690 162.507192 163.231706 165.713747 169.974245
 [85] 171.215692 171.750580 174.071217 180.409174 176.314912 179.613860
 [91] 181.527566 186.129532 185.897475 188.352366 190.521159 190.483108
 [97] 195.138711 196.973353 197.144475 196.515225
apply(X, 2, min) # 列ごとに最小値
        y         x         z 
 3.835356  1.000000 -3.323194 

4 カテゴリ変数ごとの関数に適応

カテゴリ変数ごとに平均値を求めるようなことはよくします。こういうときはtapplyが使えます。

with(df01, tapply(y, d, mean))
        A         B         C 
 95.13672 101.89341 107.29768 

これだけならばxtabs(y ~ d, data=df01)を用いても同様ですが、2位グループのスコアを求めるような処理も同様にかけます。

with(df01, tapply(y, d, function(v){
    unique(sort(v))[2]
}))
        A         B         C 
 9.878820 22.831101  5.836006 

5 慣れたら便利

最近は他のプログラミング言語でもラムダ式は一般化したのでそうでもないでもですが、慣れるまで違和感があるかも知れません。しかし、覚えたら便利なので、積極的に使っていきましょう。