分组功能(tapply,by,aggregate)和* apply系列


狗头军师
2025-03-17 08:43:35 (25天前)

每当我想在R中执行“ map” py任务时,我通常都会尝试使用该apply系列中的函数。

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

有人可以解释何时使用哪一种吗?

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

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

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

apply(matrix, 1/2, f):输入是一个矩阵。输出是一个向量,其中element i是f(矩阵的行/ col i)
tapply(vector, grouping, f):输出是一个矩阵/数组,其中矩阵/数组中的元素是向量f分组g中的值,并g被推送到行/列名
by(dataframe, grouping, f):让g成为一个分组。适用f于组/数据框的每一列。漂亮地打印f每列的分组和值。
aggregate(matrix, grouping, f):类似于by,但不是将输出漂亮地打印出来,聚合将所有内容粘贴到数据框中。
附带的问题:我还没有学会摆弄或重塑-是否会全部取代plyr或reshape全部取代?

2 条回复
  1. 1# v-star*위위 | 2020-07-27 15-03

    R有许多 apply函数,这些函数在帮助文件(例如?apply)中进行了详细描述。但是,它们足够多,刚开始使用的用户可能很难决定哪个适合他们的情况,甚至难以记住它们。他们可能有一个普遍的感觉,即“我应该在这里使用 apply函数”,但是一开始很难保持所有内容的直接。

    尽管* apply家族的许多功能(在非常受欢迎的plyr软件包中都涵盖了这一事实(在其他答案中已指出)),但基本功能仍然有用并且值得了解。

    此答案旨在充当新用户的路标,以帮助将其定向到针对其特定问题的正确 apply函数。注意,这并不是要简单地反省或替换R文档!希望这个答案可以帮助您确定哪个 apply功能适合您的情况,然后由您自己进行进一步的研究。除了一个例外,将不会解决性能差异。

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

    # Two dimensional matrix
    M <- matrix(seq(1,16), 4, 4)

    # apply min to rows

    1. apply(M, 1, min)
    2. [1] 1 2 3 4

    # apply max to columns

    1. apply(M, 2, max)
    2. [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。

    lapply - 当你想一个函数应用于又将列表中的每个元素,并得到一个列表。

    这是许多其他* apply函数的主力军。剥离他们的代码,您将经常在lapply下面找到它们。

    x <- list(a = 1, b = 1:3, c = 10:100)
    lapply(x, FUN = length)
    $a
    [1] 1
    $b

    1. [1] 3
    2. $c
    3. [1] 91
    4. lapply(x, FUN = sum)
    5. $a
    6. [1] 1
    7. $b
    8. [1] 6
    9. $c
    10. [1] 5005

    sapply - 当你想一个函数应用于又将列表中的每个元素,但是你想有一个向量回来,而不是一个列表。

    如果发现自己在打字unlist(lapply(…)),请停下来考虑 sapply。

    1. x <- list(a = 1, b = 1:3, c = 10:100)

    # Compare with above; a named vector, not a list

    1. sapply(x, FUN = length)
    2. a b c
    3. 1 3 91
    4. sapply(x, FUN = sum)
    5. a b c
    6. 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 - with 的包装,因此可以保证返回列表。mapplySIMPLIFY = FALSE

    Map(sum, 1:5, 1:5, 1:5)

    1. [[1]]
    2. [1] 3
    3. [[2]]
    4. [1] 6
    5. [[3]]
    6. [1] 9
    7. [[4]]
    8. [1] 12
    9. [[5]]
    10. [1] 15

    rapply - 当你想给一个函数应用到的每个元素嵌套列表结构,递归。

    为了让您了解一些不常见rapply的信息,我在首次发布此答案时就忘记了!显然,我敢肯定会有很多人使用它,但是YMMV。rapply最好用用户定义的函数来说明:

    # Append ! to string, otherwise increment

    1. myFun <- function(x){
    2. if(is.character(x)){
    3. return(paste(x,"!",sep=""))
    4. }
    5. else{
    6. return(x + 1)
    7. }
    8. }

    #A nested list structure

    1. l <- list(a = list(a1 = "Boo", b1 = 2, c1 = "Eeek"),
    2. b = 3, c = "Yikes",
    3. 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))
    将x每个子组中的值相加y:

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

    可以处理更复杂的示例,其中子组由几个因素列表的唯一组合定义。tapply在本质上分裂应用-结合是常见的功能在R(类似aggregate,by,ave,ddply,等等)因此,它的黑色羊状态。

登录 后才能参与评论