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
がもっとも単純な関数で、戻り値としてリストを返してきます。
[[1]]
[1] "列名B"
[[2]]
[1] "列名C"
[[3]]
[1] "列名A"
第1引数がベクターもしくはリストで、第2引数がベクターもしくはリストのそれぞれの要素を処理していく関数となります。
lapply
に渡す関数の引数が複数ある場合は、lapply
の第3引数以降に、例えば以下のように指定します。
[[1]]
[1] "列名Bです"
[[2]]
[1] "列名Cです"
[[3]]
[1] "列名Aです"
2.2 sapply
戻り値がリストのままでは使いづらいことが多いので、ラッパー関数sapply
が用意されていて、ベクトルで結果を得ることができます。
B C A
"列名B" "列名C" "列名A"
以下のようにオプションをつけると、sapply
はlapply
と同じ動作になります。
3 引数が行列もしくはデータフレーム
引数が行列もしくはデータフレームのときはapply
関数を用います。行ごと、もしくは列ごとに関数を用いることができます。
まずはmean関数と行列にする都合で、numeric型の列だけ選んでおきます。
3.1 引数がデータフレーム
第2引数が1
だと行ごとの処理、2
だと列ごとの処理になります。
[1] 2.148507 2.808693 3.592545 3.408740 5.862681 6.275644
[7] 6.859732 8.381733 9.319093 10.425042 10.628468 12.352579
[13] 13.321620 13.771991 15.396994 16.214455 17.649765 18.841002
[19] 19.054818 20.632367 21.280506 22.435104 23.430766 24.534064
[25] 25.546526 26.115597 27.674055 27.837187 29.340145 30.395691
[31] 30.888120 32.165604 32.604890 34.813334 35.257019 36.668818
[37] 37.109323 37.843648 39.003415 40.272893 41.496002 42.490272
[43] 43.088541 43.963004 45.321158 46.251095 47.050991 48.548980
[49] 49.253420 50.412183 51.510090 52.232884 53.769973 53.947695
[55] 55.288680 56.044641 57.564320 58.426295 59.562063 60.338447
[61] 60.941623 62.750436 63.174948 64.332510 65.525537 66.639497
[67] 67.872272 68.323446 69.373623 70.550177 71.429091 71.914146
[73] 73.081721 74.394770 75.465444 76.183336 77.817141 78.642595
[79] 79.481254 79.975997 80.835012 82.748137 82.642287 84.298794
[85] 85.356045 86.139909 87.098656 88.725484 89.724155 90.189025
[91] 91.773052 92.272288 92.792678 93.984802 95.504618 96.421991
[97] 97.574773 98.687522 99.859107 100.283764
y x z
101.5788253 50.5000000 0.4263418
$y
[1] 101.5788
$x
[1] 50.5
$z
[1] 0.4263418
行列やデータフレームの行ごと、列ごとの合計と平均をとるだけであれば、colSums
,
rowSums
, colMeans
,
rowMeans
を使う方が高速です。
3.2 引数が行列
行列でもデータフレームと同様に処理できます。
[1] 5.575355 4.482252 6.184366 6.936873 13.816381 12.164989
[7] 13.736850 16.446137 19.829365 20.956880 21.317179 26.685183
[13] 26.979306 25.897898 30.691625 32.537407 37.106218 38.578099
[19] 35.372825 39.539666 42.129310 43.019563 46.961406 51.341433
[25] 51.698436 51.281754 55.722249 55.012191 58.070626 58.722266
[31] 59.277179 64.024715 65.220989 69.353020 70.366368 71.185812
[37] 73.143104 74.723164 77.275330 81.930696 82.361660 84.882314
[43] 86.906068 86.197302 89.603207 91.183188 94.284516 97.763282
[49] 101.954752 101.115562 103.162408 103.865940 110.045337 108.443894
[55] 110.873589 110.315316 117.263397 116.860230 118.132124 120.010923
[61] 120.397517 125.840065 126.425628 129.218537 132.564670 134.331262
[67] 135.392665 137.607316 138.151054 141.679776 143.157877 143.297121
[73] 143.434346 149.167708 151.936342 152.437569 156.760725 158.639181
[79] 159.063902 160.432364 161.307687 162.921173 165.104194 167.387090
[85] 169.898819 171.886070 173.277552 177.700193 178.291831 180.296001
[91] 182.220004 186.829930 183.994168 188.078932 191.950919 192.471836
[97] 196.330529 196.689377 199.368327 201.422797
y x z
4.482252 1.000000 -3.194494
4 カテゴリ変数ごとの関数に適応
カテゴリ変数ごとに平均値を求めるようなことはよくします。こういうときはtapply
が使えます。
A B C
103.82354 106.06086 89.68655
これだけならばxtabs(y ~ d, data=df01)
を用いても同様ですが、2位グループのスコアを求めるような処理も同様にかけます。
A B C
16.446137 6.184366 13.736850
5 引数の関数に渡す引数
apply
関数群は自分が利用しない引数を、そのまま引数の関数に受け渡します。以下の例では、sapply
に渡すmean
関数に第2引数na.rm = TRUE
を与えています。
y x z
NA 50.5000000 0.4263418
y x z
102.5485573 50.5000000 0.4263418
なお、sapply(df02, function(x) mean(x, na.rm = TRUE) )
と書いても同じ結果になります。
6 関数の省略表記
R
4.1から、function(x){ ... }
を\(x){ ... }
と書けるようになっていて、apply
関数群での利用が多くなっていくかも知れません。
7 慣れたら便利
最近は他のプログラミング言語でもラムダ式は一般化したのでそうでもないでもですが、慣れるまで違和感があるかも知れません。しかし、覚えたら便利なので、積極的に使っていきましょう。