分组函数(tapply,by,aggregate)和* apply family
每当我想在R中做一些“映射”py时,我通常会尝试在apply
系列中使用函数。
但是,我从来没有完全理解它们之间的差异 - 如何将输入/分组输入应用到函数,输出将会是什么样子,甚至输入什么样的东西,所以{ sapply
, lapply
等}我经常只是经历他们,直到我得到我想要的。
有人可以解释如何使用哪一个?
我目前(可能不正确/不完整)的理解是......
sapply(vec, f)
:输入是一个向量。 输出是一个向量/矩阵,其中元素i
是f(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或重塑 - 将plyr
或reshape
完全取代所有这些?
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
如果你想要二维矩阵的行/列平均值或和,一定要调查高度优化的闪电般的colMeans
, rowMeans
, colSums
, rowSums
。
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中常见的分裂应用合并函数( aggregate
, by
, ave
, ddply
等),因此它的黑羊状态。
在附注中,下面是各种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
函数更困难。
在我每天的使用中, plyr
和reshape
函数几乎替代了所有这些函数。 但是,从Intro到Plyr文档也是如此:
相关函数tapply
和sweep
在plyr
没有相应的功能,并保持有用。 merge
对于汇总和原始数据的结合非常有用。
从http://www.slideshare.net/hadley/plyr-one-data-analytic-strategy的幻灯片21:
(希望很明显, apply
对应于@哈德利的aaply
和aggregate
对应于@哈德利的ddply
等。幻灯片20相同的幻灯片将澄清,如果你不从这个图像得到它。)
(在左边是输入,在上面是输出)
链接地址: http://www.djcxy.com/p/38277.html上一篇: Grouping functions (tapply, by, aggregate) and the *apply family