グループ化関数(tapply、by、aggregate)と*applyファミリー 質問する

グループ化関数(tapply、by、aggregate)と*applyファミリー 質問する

R で何かを「マップ」したいときは、通常、applyファミリー内の関数を使用するようにしています。

しかし、それらの違い、つまり、{ sapplylapplyなど} が関数を入力/グループ化された入力に適用する方法、出力がどのようになるか、さらには入力が何であるかなどを完全に理解したことがないので、必要な結果が得られるまで、多くの場合、それらすべてを調べます。

どれをいつどのように使うのか説明してもらえますか?

私の現在の(おそらく間違っている/不完全な)理解は...

  1. sapply(vec, f): 入力はベクトルです。出力はベクトル/行列で、要素iは です。出力に複数の要素があるf(vec[i])場合は行列になります。f

  2. lapply(vec, f): と同じですsapplyが、出力はリストになりますか?

  3. apply(matrix, 1/2, f): 入力は行列です。出力はベクトルで、要素iは f(行列の行/列 i) です。
  4. tapply(vector, grouping, f): 出力は行列/配列であり、行列/配列の要素はベクトルのfグループ化の値であり、行/列名にプッシュされます。gg
  5. by(dataframe, grouping, f):gをグループ化します。fグループ/データフレームの各列に適用します。グループ化とf各列の値をきれいに印刷します。
  6. 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ください。rowMeanscolSumsrowSums

  • 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厄介者となっています。aggregatebyaveddply

おすすめ記事