R で何かを「マップ」したいときは、通常、apply
ファミリー内の関数を使用するようにしています。
しかし、それらの違い、つまり、{ sapply
、lapply
など} が関数を入力/グループ化された入力に適用する方法、出力がどのようになるか、さらには入力が何であるかなどを完全に理解したことがないので、必要な結果が得られるまで、多くの場合、それらすべてを調べます。
どれをいつどのように使うのか説明してもらえますか?
私の現在の(おそらく間違っている/不完全な)理解は...
sapply(vec, f)
: 入力はベクトルです。出力はベクトル/行列で、要素i
は です。出力に複数の要素があるf(vec[i])
場合は行列になります。f
lapply(vec, f)
: と同じですsapply
が、出力はリストになりますか?apply(matrix, 1/2, f)
: 入力は行列です。出力はベクトルで、要素i
は f(行列の行/列 i) です。tapply(vector, grouping, f)
: 出力は行列/配列であり、行列/配列の要素はベクトルのf
グループ化の値であり、行/列名にプッシュされます。g
g
by(dataframe, grouping, f)
:g
をグループ化します。f
グループ/データフレームの各列に適用します。グループ化とf
各列の値をきれいに印刷します。aggregate(matrix, grouping, f)
: と似ていますby
が、出力をきれいに印刷する代わりに、aggregate はすべてをデータフレームに貼り付けます。
余談ですが、私はまだ plyr や reshape を学んでいません。これらをすべて完全に置き換えることplyr
はできますか?reshape
ベストアンサー1
R には多くの *apply 関数があり、ヘルプ ファイル (例?apply
) でわかりやすく説明されています。ただし、関数が多すぎるため、初心者は状況に応じてどれが適切かを判断したり、すべてを覚えたりするのが困難な場合があります。「ここでは *apply 関数を使用する必要がある」という大まかな感覚は持っているかもしれませんが、最初はすべてを把握するのは難しい場合があります。
*apply ファミリーの機能の多くは非常に人気のあるパッケージでカバーされているという事実(他の回答で言及されている)にもかかわらずplyr
、基本関数は依然として有用であり、知っておく価値があります。
この回答は、新しいユーザーに対して、特定の問題に対して適切な *apply 関数を導くための一種の道標として機能することを目的としています。これは、R ドキュメントを単に繰り返したり置き換えたりするものではありません。この回答が、どの *apply 関数が状況に適しているかを判断するのに役立つことを願っています。その後、さらに調査するのはあなた次第です。1 つの例外を除いて、パフォーマンスの違いについては説明しません。
apply -関数を行列(および高次元の類似物)の行または列に適用する場合。最初に行列に強制変換されるため、データ フレームには一般に推奨されません。
# Two dimensional matrix M <- matrix(seq(1,16), 4, 4) # apply min to rows apply(M, 1, min) [1] 1 2 3 4 # apply max to columns apply(M, 2, max) [1] 4 8 12 16 # 3 dimensional array M <- array( seq(32), dim = c(4,4,2)) # Apply sum across each M[*, , ] - i.e Sum across 2nd and 3rd dimension apply(M, 1, sum) # Result is one-dimensional [1] 120 128 136 144 # Apply sum across each M[*, *, ] - i.e Sum across 3rd dimension apply(M, c(1,2), sum) # Result is two-dimensional [,1] [,2] [,3] [,4] [1,] 18 26 34 42 [2,] 20 28 36 44 [3,] 22 30 38 46 [4,] 24 32 40 48
2D 行列の行/列の平均または合計が必要な場合は、高度に最適化された超高速の 、、、 を必ず調べて
colMeans
ください。rowMeans
colSums
rowSums
lapply -リストの各要素に順番に関数を適用し、リストを返したい場合。
これは、他の多くの *apply 関数の主力です。コードを詳しく調べると、
lapply
その下にあるものが見つかることがよくあります。x <- list(a = 1, b = 1:3, c = 10:100) lapply(x, FUN = length) $a [1] 1 $b [1] 3 $c [1] 91 lapply(x, FUN = sum) $a [1] 1 $b [1] 6 $c [1] 5005
sapply -リストの各要素に順番に関数を適用したいが、リストではなくベクトルを返したい場合。
入力中に気づいたら
unlist(lapply(...))
、立ち止まって考えてみましょうsapply
。x <- list(a = 1, b = 1:3, c = 10:100) # Compare with above; a named vector, not a list sapply(x, FUN = length) a b c 1 3 91 sapply(x, FUN = sum) a b c 1 6 5005
より高度な使用法では
sapply
、適切な場合は結果を多次元配列に強制変換しようとします。たとえば、関数が同じ長さのベクトルを返す場合、sapply
それらを行列の列として使用します。sapply(1:5,function(x) rnorm(3,x))
関数が 2 次元行列を返す場合、
sapply
返される各行列を単一の長いベクトルとして扱い、基本的に同じことを行います。sapply(1:5,function(x) matrix(x,2,2))
を指定しない限り
simplify = "array"
、個々の行列を使用して多次元配列を構築します。sapply(1:5,function(x) matrix(x,2,2), simplify = "array")
もちろん、これらの各動作は、関数が同じ長さまたは次元のベクトルまたは行列を返すことを条件とします。
vapply -使用したい
sapply
が、コードからもう少し速度を絞り出す必要がある場合やより型安全性が欲しい。の場合
vapply
、基本的には、関数が返すものの種類の例を R に提供することになります。これにより、返される値を単一のアトミック ベクトルに収まるように強制する時間を節約できます。x <- list(a = 1, b = 1:3, c = 10:100) #Note that since the advantage here is mainly speed, this # example is only for illustration. We're telling R that # everything returned by length() should be an integer of # length 1. vapply(x, FUN = length, FUN.VALUE = 0L) a b c 1 3 91
mapply -複数のデータ構造 (例: ベクトル、リスト) があり、各データ構造の最初の要素に関数を適用し、次に各データ構造の 2 番目の要素に適用するなどして、結果をベクトル/配列に強制変換する場合に使用します
sapply
。これは、関数が複数の引数を受け入れる必要があるという意味で多変量です。
#Sums the 1st elements, the 2nd elements, etc. mapply(sum, 1:5, 1:5, 1:5) [1] 3 6 9 12 15 #To do rep(1,4), rep(2,3), etc. mapply(rep, 1:4, 4:1) [[1]] [1] 1 1 1 1 [[2]] [1] 2 2 2 [[3]] [1] 3 3 [[4]] [1] 4
Map -のラッパー
mapply
なのでSIMPLIFY = FALSE
、リストを返すことが保証されます。Map(sum, 1:5, 1:5, 1:5) [[1]] [1] 3 [[2]] [1] 6 [[3]] [1] 9 [[4]] [1] 12 [[5]] [1] 15
rapply -ネストされたリスト構造の各要素に関数を再帰的に適用する場合に使用します。
どれほど珍しいかお伝えすると
rapply
、この回答を最初に投稿したときには忘れていました。もちろん、多くの人が使用していると思いますが、人によって異なります。rapply
ユーザー定義関数を適用すると、最もよく説明できます。# Append ! to string, otherwise increment myFun <- function(x){ if(is.character(x)){ return(paste(x,"!",sep="")) } else{ return(x + 1) } } #A nested list structure l <- list(a = list(a1 = "Boo", b1 = 2, c1 = "Eeek"), b = 3, c = "Yikes", d = list(a2 = 1, b2 = list(a3 = "Hey", b3 = 5))) # Result is named vector, coerced to character rapply(l, myFun) # Result is a nested list like l, with values altered rapply(l, myFun, how="replace")
tapply -ベクトルのサブセットに関数を適用する場合、サブセットは他のベクトル (通常は因子) によって定義されます。
*applyファミリーの厄介者。ヘルプファイルで「不規則配列」というフレーズが使われているのは少し混乱するですが、実はとても簡単です。
ベクトル:
x <- 1:20
グループを定義する因子(同じ長さ!):
y <- factor(rep(letters[1:5], each = 4))
x
によって定義される各サブグループ内の値を合計しますy
。tapply(x, y, sum) a b c d e 10 26 42 58 74
サブグループが複数の因子のリストの一意の組み合わせによって定義される、より複雑な例も処理できます。 は、R で一般的な split-apply-combine 関数 (、、、など) と精神的に似ています。そのため、
tapply
厄介者となっています。aggregate
by
ave
ddply