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

时间:2010-08-17 18:31:13

标签: r lapply sapply tapply r-faq

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

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

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

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

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

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

  3. apply(matrix, 1/2, f):输入是一个矩阵。 output是一个向量,其中元素i是f(矩阵的row / col i)
  4. tapply(vector, grouping, f):output是一个矩阵/数组,其中矩阵/数组中的元素是向量的分组f处的g的值,{{1} }被推送到行/列名称
  5. g:让by(dataframe, grouping, f)成为分组。将g应用于组/数据框的每一列。在每列打印分组和f的值。
  6. f:与aggregate(matrix, grouping, f)类似,但不是打印输出,而是聚合将所有内容都粘贴到数据框中。
  7. 附带问题:我还没有学过plyr或重塑 - byplyr会完全取代所有这些吗?

10 个答案:

答案 0 :(得分:1258)

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
    

    如果您想要2D矩阵的行/列平均值或总和,请确保 调查高度优化,闪电般快速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 - 当您有多个数据结构时(例如 向量,列表)并且您想要将函数应用于第1个元素 每个,然后是每个的第二个元素等,强制结果 到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
    
  • 地图 - 包含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是多么罕见,我在第一次发布此答案时就忘记了!显然,我相信很多人都会使用它,但是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 - 当您要将某个功能应用于子集时 向量和子集由一些其他向量定义,通常是a 因素。

    *的黑羊适用于各种各样的家庭。帮助文件的使用 “ragged array”这个短语可能有点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(aggregatebyaveddply等。因此它的 黑羊身份。

答案 1 :(得分:180)

在旁注中,以下是各种plyr函数与基本*apply函数的对应方式(从plyr网页{1}的介绍到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函数在我的日常使用中已经取代了几乎所有这些函数。但是,也可以从介绍到Plyr文件:

  

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

答案 2 :(得分:127)

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

apply, sapply, lapply, by, aggregate

(希望很明显,apply对应@Hadley的aaplyaggregate对应@Hadley的ddply等。同一幻灯片的幻灯片20将澄清你是否愿意从这张图片中得到它。)

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

答案 3 :(得分:95)

首先从Joran's excellent answer开始 - 怀疑任何事情都可以更好。

然后以下助记符可能有助于记住每个之间的区别。虽然有些是显而易见的,但有些可能不那么明显 - 因为你可以在Joran的讨论中找到理由。

<强>助记符

  • lapply是一个列表,适用于列表或向量并返回列表。
  • sapply简单 lapply(函数默认为在可能的情况下返回向量或矩阵)
  • vapply已验证的应用(允许预先指定返回对象类型)
  • rapply递归申请嵌套列表,即列表中的列表
  • tapply标记的适用于标记标识子集的地方
  • apply 泛型:将函数应用于矩阵的行或列(或更一般地说,应用于数组的维度)

构建正确的背景

如果使用apply家庭仍觉得您有点陌生,那么可能是您错过了关键观点。

这两篇文章可以提供帮助。它们提供了必要的背景来激发apply函数族提供的函数式编程技术

Lisp的用户将立即认识到这种范式。如果你不熟悉Lisp,一旦你了解了FP,你就可以获得一个强大的观点来使用R - 而且apply会更有意义。

答案 4 :(得分:44)

因为我意识到这篇文章的(非常优秀的)答案缺乏byaggregate解释。这是我的贡献。

BY

by函数,如文档中所述,可以作为&#34;包装器&#34;为tapply。当我们想要计算by无法处理的任务时,会产生tapply的强大功能。一个例子是这段代码:

ct <- tapply(iris$Sepal.Width , iris$Species , summary )
cb <- by(iris$Sepal.Width , iris$Species , summary )

 cb
iris$Species: setosa
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.300   3.200   3.400   3.428   3.675   4.400 
-------------------------------------------------------------- 
iris$Species: versicolor
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.000   2.525   2.800   2.770   3.000   3.400 
-------------------------------------------------------------- 
iris$Species: virginica
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.200   2.800   3.000   2.974   3.175   3.800 


ct
$setosa
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.300   3.200   3.400   3.428   3.675   4.400 

$versicolor
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.000   2.525   2.800   2.770   3.000   3.400 

$virginica
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.200   2.800   3.000   2.974   3.175   3.800 

如果我们打印这两个对象ctcb,我们就会基本上&#34;具有相同的结果,唯一的区别在于它们的显示方式和不同的class属性,分别为by的{​​{1}}和cb的{​​{1}}。< / p>

正如我所说,array的力量在我们无法使用ct时出现;以下代码就是一个例子:

by

R说参数必须具有相同的长度,比如说#34;我们想要计算tapply tapply(iris, iris$Species, summary ) Error in tapply(iris, iris$Species, summary) : arguments must have same length 所有变量的summary沿iris&#34;:但是R不能这样做,因为它不知道如何处理。

使用Species函数R为by类调度特定方法,然后让data frame函数工作,即使第一个参数的长度(以及类型也不同)

summary

确实有效,结果非常令人惊讶。它是bywork <- by(iris, iris$Species, summary ) bywork iris$Species: setosa Sepal.Length Sepal.Width Petal.Length Petal.Width Species Min. :4.300 Min. :2.300 Min. :1.000 Min. :0.100 setosa :50 1st Qu.:4.800 1st Qu.:3.200 1st Qu.:1.400 1st Qu.:0.200 versicolor: 0 Median :5.000 Median :3.400 Median :1.500 Median :0.200 virginica : 0 Mean :5.006 Mean :3.428 Mean :1.462 Mean :0.246 3rd Qu.:5.200 3rd Qu.:3.675 3rd Qu.:1.575 3rd Qu.:0.300 Max. :5.800 Max. :4.400 Max. :1.900 Max. :0.600 -------------------------------------------------------------- iris$Species: versicolor Sepal.Length Sepal.Width Petal.Length Petal.Width Species Min. :4.900 Min. :2.000 Min. :3.00 Min. :1.000 setosa : 0 1st Qu.:5.600 1st Qu.:2.525 1st Qu.:4.00 1st Qu.:1.200 versicolor:50 Median :5.900 Median :2.800 Median :4.35 Median :1.300 virginica : 0 Mean :5.936 Mean :2.770 Mean :4.26 Mean :1.326 3rd Qu.:6.300 3rd Qu.:3.000 3rd Qu.:4.60 3rd Qu.:1.500 Max. :7.000 Max. :3.400 Max. :5.10 Max. :1.800 -------------------------------------------------------------- iris$Species: virginica Sepal.Length Sepal.Width Petal.Length Petal.Width Species Min. :4.900 Min. :2.200 Min. :4.500 Min. :1.400 setosa : 0 1st Qu.:6.225 1st Qu.:2.800 1st Qu.:5.100 1st Qu.:1.800 versicolor: 0 Median :6.500 Median :3.000 Median :5.550 Median :2.000 virginica :50 Mean :6.588 Mean :2.974 Mean :5.552 Mean :2.026 3rd Qu.:6.900 3rd Qu.:3.175 3rd Qu.:5.875 3rd Qu.:2.300 Max. :7.900 Max. :3.800 Max. :6.900 Max. :2.500 类的一个对象,沿by(例如,对于每个类)计算每个变量的Species

请注意,如果第一个参数是summary,则调度函数必须具有该类对象的方法。例如,我们将此代码与data frame函数一起使用,我们将拥有完全没有意义的代码:

mean

AGGREGATE

如果我们以这种方式使用它,{p> by(iris, iris$Species, mean) iris$Species: setosa [1] NA ------------------------------------------- iris$Species: versicolor [1] NA ------------------------------------------- iris$Species: virginica [1] NA Warning messages: 1: In mean.default(data[x, , drop = FALSE], ...) : argument is not numeric or logical: returning NA 2: In mean.default(data[x, , drop = FALSE], ...) : argument is not numeric or logical: returning NA 3: In mean.default(data[x, , drop = FALSE], ...) : argument is not numeric or logical: returning NA 可被视为另一种不同的使用方式aggregate

tapply

两个直接的区别在于at <- tapply(iris$Sepal.Length , iris$Species , mean) ag <- aggregate(iris$Sepal.Length , list(iris$Species), mean) at setosa versicolor virginica 5.006 5.936 6.588 ag Group.1 x 1 setosa 5.006 2 versicolor 5.936 3 virginica 6.588 的第二个参数必须是一个列表,而aggregate 可以(非强制性)是一个列表并且tapply的输出是数据框,而aggregate的输出是tapply

array的强大之处在于它可以使用aggregate参数轻松处理数据的子集,并且它还具有subset个对象和ts的方法。 / p>

在某些情况下,这些元素使formula更容易使用aggregate。 以下是一些示例(文档中提供):

tapply

我们可以使用ag <- aggregate(len ~ ., data = ToothGrowth, mean) ag supp dose len 1 OJ 0.5 13.23 2 VC 0.5 7.98 3 OJ 1.0 22.70 4 VC 1.0 16.77 5 OJ 2.0 26.06 6 VC 2.0 26.14 实现相同的功能,但语法稍微困难,输出(在某些情况下)可读性较差:

tapply

还有一些时候我们无法使用att <- tapply(ToothGrowth$len, list(ToothGrowth$dose, ToothGrowth$supp), mean) att OJ VC 0.5 13.23 7.98 1 22.70 16.77 2 26.06 26.14 by,我们必须使用tapply

aggregate

我们无法在一次调用中使用 ag1 <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, mean) ag1 Month Ozone Temp 1 5 23.61538 66.73077 2 6 29.44444 78.22222 3 7 59.11538 83.88462 4 8 59.96154 83.96154 5 9 31.44828 76.89655 获取以前的结果,但我们必须为每个元素计算tapply的平均值,然后将它们组合起来(还要注意我们必须调用{{1} },因为Month函数的na.rm = TRUE方法默认为formula}:

aggregate

虽然使用na.action = na.omit我们实际上无法实现,但实际上以下函数调用会返回错误(但很可能与提供的函数ta1 <- tapply(airquality$Ozone, airquality$Month, mean, na.rm = TRUE) ta2 <- tapply(airquality$Temp, airquality$Month, mean, na.rm = TRUE) cbind(ta1, ta2) ta1 ta2 5 23.61538 65.54839 6 29.44444 79.10000 7 59.11538 83.90323 8 59.96154 83.96774 9 31.44828 76.90000 相关):

by

其他时候结果是相同的,差异只是在类中(然后是如何显示/打印的,而不仅仅是 - 例如,如何将其子集化)对象:

mean

以前的代码实现了相同的目标和结果,在某些方面,使用什么工具只是个人品味和需求的问题;前两个对象在子集化方面的需求非常不同。

答案 5 :(得分:31)

有许多很好的答案可以讨论每个函数的用例差异。答案都没有讨论性能上的差异。这是合理的,因为各种函数期望各种输入并产生各种输出,但是它们中的大多数具有通过系列/组来评估的一般共同目标。我的回答是关注绩效。由于上述原因,来自向量的输入创建包含在时序中,因此不测量apply函数。

我一次测试了两个不同的函数sumlength。测试的体积输入为50M,输出为50K。我还提供了两个当前流行的软件包,这些软件包在提出问题时未被广泛使用,data.tabledplyr。如果你的目标是获得良好的表现,那么两者绝对值得一看。

library(dplyr)
library(data.table)
set.seed(123)
n = 5e7
k = 5e5
x = runif(n)
grp = sample(k, n, TRUE)

timing = list()

# sapply
timing[["sapply"]] = system.time({
    lt = split(x, grp)
    r.sapply = sapply(lt, function(x) list(sum(x), length(x)), simplify = FALSE)
})

# lapply
timing[["lapply"]] = system.time({
    lt = split(x, grp)
    r.lapply = lapply(lt, function(x) list(sum(x), length(x)))
})

# tapply
timing[["tapply"]] = system.time(
    r.tapply <- tapply(x, list(grp), function(x) list(sum(x), length(x)))
)

# by
timing[["by"]] = system.time(
    r.by <- by(x, list(grp), function(x) list(sum(x), length(x)), simplify = FALSE)
)

# aggregate
timing[["aggregate"]] = system.time(
    r.aggregate <- aggregate(x, list(grp), function(x) list(sum(x), length(x)), simplify = FALSE)
)

# dplyr
timing[["dplyr"]] = system.time({
    df = data_frame(x, grp)
    r.dplyr = summarise(group_by(df, grp), sum(x), n())
})

# data.table
timing[["data.table"]] = system.time({
    dt = setnames(setDT(list(x, grp)), c("x","grp"))
    r.data.table = dt[, .(sum(x), .N), grp]
})

# all output size match to group count
sapply(list(sapply=r.sapply, lapply=r.lapply, tapply=r.tapply, by=r.by, aggregate=r.aggregate, dplyr=r.dplyr, data.table=r.data.table), 
       function(x) (if(is.data.frame(x)) nrow else length)(x)==k)
#    sapply     lapply     tapply         by  aggregate      dplyr data.table 
#      TRUE       TRUE       TRUE       TRUE       TRUE       TRUE       TRUE 

# print timings
as.data.table(sapply(timing, `[[`, "elapsed"), keep.rownames = TRUE
              )[,.(fun = V1, elapsed = V2)
                ][order(-elapsed)]
#          fun elapsed
#1:  aggregate 109.139
#2:         by  25.738
#3:      dplyr  18.978
#4:     tapply  17.006
#5:     lapply  11.524
#6:     sapply  11.326
#7: data.table   2.686

答案 6 :(得分:22)

值得一提的是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
## ...

答案 7 :(得分:22)

尽管这里有很多好的答案,还有2个基本功能值得一提,有用的outer函数和模糊的eapply函数

<强>外

outer是一个非常有用的功能,隐藏为一个更普通的功能。如果您阅读outer的帮助,其说明如下:

The outer product of the arrays X and Y is the array A with dimension  
c(dim(X), dim(Y)) where element A[c(arrayindex.x, arrayindex.y)] =   
FUN(X[arrayindex.x], Y[arrayindex.y], ...).

这使得它似乎只对线性代数类型的东西有用。但是,它可以像mapply一样用于将函数应用于两个输入向量。不同之处在于mapply将函数应用于前两个元素,然后应用于后两个元素等,而outer将函数应用于来自第一个向量的一个元素和来自第二个向量的一个元素的每个组合。 。例如:

 A<-c(1,3,5,7,9)
 B<-c(0,3,6,9,12)

mapply(FUN=pmax, A, B)

> mapply(FUN=pmax, A, B)
[1]  1  3  6  9 12

outer(A,B, pmax)

 > outer(A,B, pmax)
      [,1] [,2] [,3] [,4] [,5]
 [1,]    1    3    6    9   12
 [2,]    3    3    6    9   12
 [3,]    5    5    6    9   12
 [4,]    7    7    7    9   12
 [5,]    9    9    9    9   12

当我有一个值向量和条件向量时,我亲自使用了这个,并希望看到哪些值符合哪些条件。

<强> eapply

eapplylapply类似,不同之处在于它不是将函数应用于列表中的每个元素,而是将函数应用于环境中的每个元素。例如,如果要在全局环境中查找用户定义函数的列表:

A<-c(1,3,5,7,9)
B<-c(0,3,6,9,12)
C<-list(x=1, y=2)
D<-function(x){x+1}

> eapply(.GlobalEnv, is.function)
$A
[1] FALSE

$B
[1] FALSE

$C
[1] FALSE

$D
[1] TRUE 

坦率地说,我不会使用它,但如果你正在构建大量的软件包或创建很多环境,它可能会派上用场。

答案 8 :(得分:8)

我最近发现了相当有用的sweep函数,并在此处添加它是为了完整性:

<强>扫描

基本思想是通过行或列方式扫描并返回修改后的数组。一个例子可以说明这一点(来源:datacamp):

假设您有一个矩阵,并希望按列standardize

dataPoints <- matrix(4:15, nrow = 4)

# Find means per column with `apply()`
dataPoints_means <- apply(dataPoints, 2, mean)

# Find standard deviation with `apply()`
dataPoints_sdev <- apply(dataPoints, 2, sd)

# Center the points 
dataPoints_Trans1 <- sweep(dataPoints, 2, dataPoints_means,"-")
print(dataPoints_Trans1)
##      [,1] [,2] [,3]
## [1,] -1.5 -1.5 -1.5
## [2,] -0.5 -0.5 -0.5
## [3,]  0.5  0.5  0.5
## [4,]  1.5  1.5  1.5
# Return the result
dataPoints_Trans1
##      [,1] [,2] [,3]
## [1,] -1.5 -1.5 -1.5
## [2,] -0.5 -0.5 -0.5
## [3,]  0.5  0.5  0.5
## [4,]  1.5  1.5  1.5
# Normalize
dataPoints_Trans2 <- sweep(dataPoints_Trans1, 2, dataPoints_sdev, "/")

# Return the result
dataPoints_Trans2
##            [,1]       [,2]       [,3]
## [1,] -1.1618950 -1.1618950 -1.1618950
## [2,] -0.3872983 -0.3872983 -0.3872983
## [3,]  0.3872983  0.3872983  0.3872983
## [4,]  1.1618950  1.1618950  1.1618950

注意:对于这个简单的例子,当然可以通过apply(dataPoints, 2, scale)

更容易地实现相同的结果

答案 9 :(得分:4)

在CRAN上最近发布的 collapse 包中,我尝试将大多数常见的Apply功能压缩为仅两个功能:

  1. dapply(数据应用)将函数应用于矩阵和数据的行或(默认)列。帧(默认)返​​回具有相同类型和相同属性的对象(除非每个对象的结果均如此)计算是原子和drop = TRUE)。对于data.frame列,其性能可与lapply媲美,对于矩阵行或列,其性能比apply快约2倍。可通过mclapply使用并行性(仅适用于MAC)。

语法:

dapply(X, FUN, ..., MARGIN = 2, parallel = FALSE, mc.cores = 1L, 
       return = c("same", "matrix", "data.frame"), drop = TRUE)

示例:

# Apply to columns:
dapply(mtcars, log)
dapply(mtcars, sum)
dapply(mtcars, quantile)
# Apply to rows:
dapply(mtcars, sum, MARGIN = 1)
dapply(mtcars, quantile, MARGIN = 1)
# Return as matrix:
dapply(mtcars, quantile, return = "matrix")
dapply(mtcars, quantile, MARGIN = 1, return = "matrix")
# Same for matrices ...
  1. BY是S3泛型,用于通过向量,矩阵和data.frame方法进行拆分应用组合计算。它明显比tapplybyaggregate快(尽管在大数据plyr上也比dplyr快)。

语法:

BY(X, g, FUN, ..., use.g.names = TRUE, sort = TRUE,
   expand.wide = FALSE, parallel = FALSE, mc.cores = 1L,
   return = c("same", "matrix", "data.frame", "list"))

示例:

# Vectors:
BY(iris$Sepal.Length, iris$Species, sum)
BY(iris$Sepal.Length, iris$Species, quantile)
BY(iris$Sepal.Length, iris$Species, quantile, expand.wide = TRUE) # This returns a matrix 
# Data.frames
BY(iris[-5], iris$Species, sum)
BY(iris[-5], iris$Species, quantile)
BY(iris[-5], iris$Species, quantile, expand.wide = TRUE) # This returns a wider data.frame
BY(iris[-5], iris$Species, quantile, return = "matrix") # This returns a matrix
# Same for matrices ...

分组变量的列表也可以提供给g

谈论性能: collapse 的主要目标是在R中促进高性能编程,并超越所有组合在一起的组合。为此,该软件包具有完整的基于C ++的快速泛型函数集:fmeanfmedianfmodefsumfprod,{{1} },fsdfvarfminfmaxffirstflastfNobsfNdistinctfscalefbetweenfwithinfHDbetweenfHDwithinflagfdiff。他们通过数据一次执行分组计算(即不拆分和重组)。

语法:

fgrowth

示例:

fFUN(x, g = NULL, [w = NULL,] TRA = NULL, [na.rm = TRUE,] use.g.names = TRUE, drop = TRUE)

在小插图中,我提供了基准。使用快速功能进行编程比使用 dplyr data.table 进行编程要快得多,尤其是在较小的数据上,在大型数据上也是如此。