sapply - R分组功能:sapply vs. lapply vs. apply. vs. tapply vs. by vs. aggregate

  显示原文与译文双语对照的内容

每当我想做点事"映射"setup.py通常在 R 中,我尝试使用一个函数在 apply 族中。 ( 问题:我还没有学习 plyr 或者 reshape --将 plyr 或者 reshape 全部替换)?

不过,我有永远无法完全理解他们的不同 [how { sapply, lapply, etc.} 将该函数应用于分组的输入/输入,输出将是什么样子,甚至是在输入什么可以be]它们全部,所以我通常只是经过,直到我得到我想要的。

有人可以解释如何使用它?

[ 我当前的( 可能不正确/不完整) 理解是。。

  1. sapply(vec, f): 输入是矢量。 输出是一个向量/矩阵,其中元素 if(vec[i]) [giving you a matrix if f has a multi-element output ]
  2. lapply(vec, f): 与 sapply 相同,但输出是一个列表?
  3. apply(matrix, 1/2, f): 输入是一个矩阵。 输出是一个向量,其中元素 i 是 f(row/col i of the matrix )
  4. tapply(vector, grouping, f): 输出是一个矩阵/数组,其中矩阵/数组中的一个元素是 gf 在一个分组的值给出了向量和 g 被推入到行/列名称
  5. by(dataframe, grouping, f): 让 g 成为分组。 将 f 应用于组/dataframe的每列。 漂亮地打印每个列的分组和 f的值。
  6. aggregate(matrix, grouping, f): 树枝盖与 by 类似,但在输出来代替优质打印,聚合一切成一个 dataframe 。]
时间:

R 有许多 *apply 函数,它们在帮助文件中巧妙地描述( 例如。 ?apply ) 有足够的理由,尽管开始用户可能很难决定哪一个适合他们的情况,甚至能记住它们。 他们可能有一个一般意义上,在 first,"我应该在这里使用 *apply 函数"对要保持它们全部笔直,但它可能会很艰难

尽管事实上( 在其他答案中注明) 是大多数的功能 plyr *apply 家族包括于极其流行的封装,该基函数保持有用和值得让人称赞。

这个答案旨在充当起路标对新用户,以帮助直接加以正确的*apply 功能为他们的特定问题。 注意,这是没有打算简单地反刍或者替换 R 文档 ! 希望这个答案能帮助你决定哪个 *apply 函数适合你的情况,然后由你来进一步研究它。 有一个例外,性能差异将不会被解决。

  • 当你想将一个函数应用到一个矩阵的行或者列的应用 - ( 和higher-dimensional相似相似) 。

    
    # 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
    
    

    如果你想要对一个 2矩阵矩阵的行/列表示,那么一定要研究高度优化的,lightning-quick colMeansrowMeanscolSumsrowSums

  • 当你想要对列表中的每个元素应用一个函数并得到一个列表时,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 上面; 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 中,它将尝试将结果强制为multi-dimensional数组,如果合适的话。 例如如果我们的函数返回相同长度的向量,sapply 将使用它们作为矩阵的列:

    
     sapply(1:5,function(x) rnorm(3,x))
    
    

    如果我们的函数返回一个 2维矩阵,sapply 会做同样的事情,把每个返回的矩阵当作一个长向量处理:

    
     sapply(1:5,function(x) matrix(x,2,2))
    
    

    除非我们指定 simplify ="array",否则它将使用单个矩阵来构建一个multi-dimensional数组:

    
     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 - 。 向量,列表),将一个函数应用到每个元素的1个元素,然后是每个元素的2个元素,等等,将结果强制为向量/数组。

    这是多变量的,你的函数必须接受多个参数。

    
    #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
    
    
  • - 一个封装映射到与 SIMPLIFY = FALSEmapply,所以保证了配置为返回一个列表。

    
    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 有多不常见,我在第一次发布这个答案时忘记了它 ! 显然,我相信很多人都使用它,但是 YMMV 。 rapply 最好用user-defined函数来说明:

    
    #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 中values:加起来

    
     tapply(x, y, sum) 
     a b c d e 
     10 26 42 58 74 
    
    

    更复杂的示例可以通过多个因素的唯一组合的唯一组合来处理。 在 split-apply-combine tapply 是类似在本质上与功能为通常在 R ( 宋体,aggregatebyaveddply,等等 ) 所以取名为黑色羊的状态。

在旁边,这里是各种 plyr 函数与基本 *apply 函数的对应关系( 从plyr网页 http://had.co.nz/plyr/的介绍到plyr文档)


Base function Input Output plyr function 
---------------------------------------
aggregate d d ddply + colwise 
apply a a/l aaply/alply 
by d l dlply 
lapply l l llply 
mapply a a/l maply/mlply 
replicate r a/l raply/rlply 
sapply l a laply 

plyr的目标之一是为每个函数提供一致的命名约定,对函数名称中的输入和输出数据类型进行编码。 它还提供了输出的一致性,在输出中,dlply()的输出很容易得到有用的输出,等等。

从概念上讲,学习 plyr 比理解基本的*apply 函数更困难。

plyrreshape 函数在我的日常使用中取代了几乎所有这些函数。 但是,也从介绍Plyr文档开始:

相关函数 tapplysweepplyr 中没有相应的函数,并且仍然有用。 merge 对于将摘要与原始数据结合起来很有用。

从一张幻灯片的21 http://www.slideshare.net/hadley/plyr-one-data-analytic-strategy:

apply, sapply, lapply, by, aggregate

( 很明显,apply 与 @Hadley's aaply 相对应,aggregate 对应于 @Hadley's ddply 等等 幻灯片 20,如果你没有从该图像获取它,则会澄清。)

( 左边是输入,顶部是输出)

首先以优秀的joran回答 --置疑任何事情都可以更好。

下面的助记符可以帮助记住每个。 在的谈论而有些则通常明显,其他人可能会这么少---对于这些你会发现 justification.

助记

  • lapply 是一个应用于列表或者向量的列表,并返回一个列表。
  • sapply 是一个简单的 lapply ( 函数默认为返回一个向量或者矩阵)
  • vapply 是的sometimes-faster ( 允许返回对象类型)
  • 于内嵌套列表 换句话说,列表) 相关 lists, rapply 是一个递归应用
  • tapply 是一个标记的应用于标记识别子集
  • apply 是通用: 对矩阵或列应用函数

构建正确的背景

如果使用 apply 家族仍然对你有点陌生,那么可能你缺少一个关键的观点。

这两篇文章可以帮助。 它们提供必要的背景方案去鼓励 函数编程技术,正在被 apply 提供的函数家族中。

Lisp的用户将立即识别这个范例。 如果你不熟悉 Lisp,假如是你的头周围 FP,你将有获得了一个强大的角度出发,以用于 R --和 apply 将使很多更有意义。

可能值得提及 aveavetapply 友好的。 它以一种形式返回结果,你可以直接将它的插入到数据框架中。


dfr <- data.frame(a=1:20, f=rep(LETTERS[1:5], each=4))
means <- tapply(dfr$a, dfr$f, mean)
## A B C D E 
## 2.5 6.5 10.5 14.5 18.5 

## great, but putting it back in the data frame is another line:

dfr$m <- means[dfr$f]

dfr$m2 <- ave(dfr$a, dfr$f, FUN=mean) # NB argument name FUN is needed!
dfr
## a f m m2
## 1 A 2.5 2.5
## 2 A 2.5 2.5
## 3 A 2.5 2.5
## 4 A 2.5 2.5
## 5 B 6.5 6.5
## 6 B 6.5 6.5
## 7 B 6.5 6.5
##. . .

基本软件包中没有与 ave 类似的基本数据框架( by 就像数据框架的tapply ) 。 但是你可以捏它:


dfr$foo <- ave(1:nrow(dfr), dfr$f, FUN=function(x) {
 x <- dfr[x,]
 sum(x$m*x$m2)
})
dfr
## a f m m2 foo
## 1 1 A 2.5 2.5 25
## 2 2 A 2.5 2.5 25
## 3 3 A 2.5 2.5 25
##.. .

...