分组函数(tapply,by,aggregate)和* apply family

每当我想在R中做一些“映射”py时,我通常会尝试在apply系列中使用函数。

但是,我从来没有完全理解它们之间的差异 - 如何将输入/分组输入应用到函数,输出将会是什么样子,甚至输入什么样的东西,所以{ sapplylapply等}我经常只是经历他们,直到我得到我想要的。

有人可以解释如何使用哪一个?

我目前(可能不正确/不完整)的理解是......

  • sapply(vec, f) :输入是一个向量。 输出是一个向量/矩阵,其中元素if(vec[i]) ,如果f具有多元素输出,则给出一个矩阵

  • lapply(vec, f) :与sapply相同,但输出是列表?

  • apply(matrix, 1/2, f) :输入是一个矩阵。 输出是一个向量,其中元素i是f(矩阵的行/列)
  • tapply(vector, grouping, f) :output是一个矩阵/数组,其中矩阵/数组中的一个元素是该矢量的分组g处的f的值,并且g被推到行/列名
  • by(dataframe, grouping, f) :让g是一个分组。 将f应用于组/数据框的每一列。 漂亮地打印每个列的分组和f的值。
  • aggregate(matrix, grouping, f)类似于by但是代替漂亮打印输出,合计枝一切成数据帧。
  • 旁边的问题:我仍然没有学会plyr或重塑 - 将plyrreshape完全取代所有这些?


    R有很多*应用功能,这些功能在帮助文件中有很好的描述(例如?apply )。 尽管如此,开始使用R可能难以确定哪一个适合他们的情况,或者甚至是全部记住它们。 他们可能有一个普遍的意思,即“我应该在这里使用一个应用函数”,但是一开始就让它们保持直线会很困难。

    尽管这个事实(在其他答案中已经指出),* apply系列的很多功能都被极受欢迎的plyr包涵盖,但是基本功能仍然有用并值得了解。

    这个答案旨在作为新用途的一种路标 ,以帮助指导他们针对其特定问题的正确*应用功能。 请注意,这并不是为了简单地反刍或替换R文档! 希望这个答案可以帮助你决定哪些应用函数适合你的情况,然后由你来进一步研究。 除了一个例外,性能差异将不会被解决。

  • 适用 - 当您想要将函数应用于矩阵(和更高维的类似物)的行或列时; 通常不建议数据帧,因为它首先会强制转换为矩阵。

    # 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
    

    如果你想要二维矩阵的行/列平均值或和,一定要调查高度优化的闪电般的colMeansrowMeanscolSumsrowSums

  • lapply - 当你想依次将一个函数应用到列表中的每个元素并返回列表。

    这是许多其他应用函数的主力。 剥离他们的代码,你会经常在下面找到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))
    

    如果我们的函数返回一个二维矩阵,则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 - 对于当你有几个数据结构(例如向量,列表),并且你想要对每个元素的第一个元素和每个元素的第二个元素应用一个函数时,将结果强制转换为一个向量/数组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 - SIMPLIFY = FALSE包装mapply ,因此保证返回一个列表。

    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最好用应用用户定义的函数示出的:

    # 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 - 当你想将一个函数应用到一个矢量的子 ,并且子集由其他矢量定义时,通常是一个因子。

    适用于家庭的黑羊,种类繁多。 帮助文件使用短语“粗糙阵列”可能有点令人困惑,但实际上它非常简单。

    矢量:

    x <- 1:20
    

    定义组的一个因素(长度相同!):

    y <- factor(rep(letters[1:5], each = 4))
    

    在由y定义的每个子组中,将x的值y

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

    更复杂的例子可以在子组由几个因素的列表的唯一组合定义的情况下处理。 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()输出很容易传递给ldply()以产生有用的输出等。

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

    在我每天的使用中, plyrreshape函数几乎替代了所有这些函数。 但是,从Intro到Plyr文档也是如此:

    相关函数tapplysweepplyr没有相应的功能,并保持有用。 merge对于汇总和原始数据的结合非常有用。


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

    (希望很明显, apply对应于@哈德利的aaplyaggregate对应于@哈德利的ddply等。幻灯片20相同的幻灯片将澄清,如果你不从这个图像得到它。)

    (在左边是输入,在上面是输出)

    链接地址: http://www.djcxy.com/p/38277.html

    上一篇: Grouping functions (tapply, by, aggregate) and the *apply family

    下一篇: Calling a javascript function recursively