r - 分组函数(tapply、by、aggregate)和 *apply 系列

标签 r lapply sapply tapply r-faq

每当我想在 R 中做一些“map”py 时,我通常会尝试使用 apply 中的函数家庭。

然而,我从来没有完全理解它们之间的区别——如何{ sapply , lapply等} 将函数应用于输入/分组输入、输出将是什么样子,甚至输入可以是什么——所以我通常只是遍历它们,直到得到我想要的。

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

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

  • sapply(vec, f) : 输入是一个向量。输出是一个向量/矩阵,其中元素 if(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 ,但不是漂亮地打印输出,聚合将所有内容都粘贴到数据帧中。

  • 附带问题:我还没有学习 plyr 或 reshape -- 会 plyrreshape完全取代所有这些?

    最佳答案

    R 有许多 *apply 函数,它们在帮助文件(例如 ?apply )中得到了巧妙的描述。然而,它们已经足够多,以至于初学者可能难以决定哪一种适合他们的情况,甚至很难记住它们。他们可能有一个普遍的感觉,即“我应该在这里使用 *apply 函数”,但一开始很难让他们保持一致。
    尽管事实上(在其他答案中指出)*apply 系列的大部分功能都包含在极受欢迎的 plyr 中。包,基本功能仍然有用,值得了解。
    这个答案旨在充当一种 路标帮助新用户引导他们使用正确的 *apply 函数来解决他们的特定问题。注意,这是 不是 旨在简单地反刍或替换 R 文档!希望这个答案可以帮助您确定哪个 *apply 函数适合您的情况,然后由您进一步研究。除了一个异常(exception),性能差异将不会得到解决。

  • 申请 - 当您想对行或列应用函数时
    一个矩阵(和更高维的类似物);通常不建议用于数据帧,因为它会首先强制转换为矩阵。
     # 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
    
    如果您想要二维矩阵的行/列均值或总和,请务必
    研究高度优化、闪电般快速的 colMeans ,rowMeans , colSums , rowSums .
  • 搭扣 - 当您想将一个函数应用于 a 的每个元素时
    依次列出并取回列表。
    这是许多其他 *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
    
  • 树胶 - 当您想将一个函数应用于 a 的每个元素时
    依次列出,但你想要一个 矢量返回,而不是列表。
    如果您发现自己在输入 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但也许需要
    从您的代码中挤出更多速度或 want more type safety .
    对于 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
    
  • 映射 - 当您有多个数据结构时(例如
    向量、列表)并且您想将函数应用于第一个元素
    每个的,然后是每个的第二个元素,等等,强制结果
    到向量/数组,如 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 - 包装到 mapplySIMPLIFY = 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是的,我第一次发布这个答案时忘记了!显然,我相信很多人都在使用它,但是 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")
    
  • 点击 - 当您想将函数应用于 时子集
    向量和子集由一些其他向量定义,通常是
    因素。
    *apply 家族的害群之马。帮助文件的使用
    短语“参差不齐的阵列”可能有点confusing ,但实际上是
    非常简单。
    向量:
     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 
    
    可以在定义子组的情况下处理更复杂的示例
    通过一系列因素的独特组合。 tapply
    在精神上类似于 split-apply-combine 功能
    常见于 R ( aggregate , by , ave , ddply 等) 因此它的
    黑羊状态。
  • 关于r - 分组函数(tapply、by、aggregate)和 *apply 系列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3505701/

    相关文章:

    r - lapply 和 R 中的保存函数

    r - 在数据帧列表上使用 lapply

    R - 将两列合并到一个数据框中,创建新的列标题,使用 lapply 和 merge 在大型数据集上重复

    r - 在 R 中保留某些列

    r - data.table 中类型为 list 的列的错误消息

    R将字符串公式转换为函数

    json - 将一个 txt 文件中的多个 JSON 对象转换为 R

    r - 带有 MS-Word 输出的 Bookdown 中的表格交叉引用?

    根据R中列表的名称重命名数据框的列

    r - 跨字符串向量迭代单词并将更改应用于单个单词