【发布时间】:2012-06-03 19:55:33
【问题描述】:
我最近在学习 R,被两个函数弄糊涂了:lapply和do.call。看起来它们只是类似于 Lisp 中的map 函数。但是为什么会有两个名称如此不同的函数呢?为什么 R 不直接使用名为 map 的函数?
【问题讨论】:
我最近在学习 R,被两个函数弄糊涂了:lapply和do.call。看起来它们只是类似于 Lisp 中的map 函数。但是为什么会有两个名称如此不同的函数呢?为什么 R 不直接使用名为 map 的函数?
【问题讨论】:
lapply类似于map,do.call不是。 lapply将函数应用于列表的所有元素,do.call调用所有函数参数在列表中的函数。所以对于n元素列表,lapply n函数调用,do.call刚刚函数呼叫。所以do.call与lapply @。希望这可以澄清你的问题。
代码示例:
do.call(sum, list(c(1, 2, 4, 1, 2), na.rm = TRUE))
和:
lapply(c(1, 2, 4, 1, 2), function(x) x + 1)
【讨论】:
虽然有很多答案,这里是我的例子供参考。 假设我们有一个数据列表:
L=list(c(1,2,3), c(4,5,6))
函数 lapply 返回一个列表。
lapply(L, sum)
上面的意思类似于下面。
list( sum( L[[1]]) , sum( L[[2]]))
现在让我们对 do.call 做同样的事情
do.call(sum, L)
意思是
sum( L[[1]], L[[2]])
在我们的示例中,它返回 21。简而言之,lapply 总是返回一个列表,而 do.call 的返回类型实际上取决于执行的函数。
【讨论】:
两者的区别是:
lapply(1:n,function,parameters)
=> 这发送 1, 参数到函数 => 这将 2, 参数发送给函数 等等
do.call
只需将 1…n 作为向量和参数发送给函数
所以在 apply 中有 n 个函数调用,在 do.call 中只有一个
【讨论】:
用最简单的话来说:
lapply() 为列表中的每个元素应用一个给定的函数,因此会有多个函数调用。
do.call() 将给定函数应用于整个列表,因此只有一个函数调用。
李>最好的学习方法是使用 R 文档中的函数示例。
【讨论】:
有一个函数叫Map,可能类似于其他语言的map:
lapply返回一个与X等长的列表,其中每个元素都是对X的对应元素应用FUN的结果。
do.call 从名称或函数以及要传递给它的参数列表构造并执行函数调用。
Map 将函数应用于给定向量的相应元素...Map 是mapply 的简单包装器,它不会尝试简化结果,类似于 Common Lisp 的 mapcar(带参数被回收,但是)。未来的版本可能允许对结果类型进行一些控制。
Map 是 mapply 的包装
lapply 是 mapply 的特例
Map 和 lapply 在很多情况下是相似的。例如这里是lapply:
lapply(iris, class)
$Sepal.Length
[1] "numeric"
$Sepal.Width
[1] "numeric"
$Petal.Length
[1] "numeric"
$Petal.Width
[1] "numeric"
$Species
[1] "factor"
同样使用Map:
Map(class, iris)
$Sepal.Length
[1] "numeric"
$Sepal.Width
[1] "numeric"
$Petal.Length
[1] "numeric"
$Petal.Width
[1] "numeric"
$Species
[1] "factor"
do.call 将一个函数作为输入并将其其他参数传递给该函数。它被广泛使用,例如,将列表组装成更简单的结构(通常使用rbind 或cbind)。
例如:
x <- lapply(iris, class)
do.call(c, x)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
"numeric" "numeric" "numeric" "numeric" "factor"
【讨论】:
do.call和Lisp中的apply差不多
do.call(cbind, x),当前版本给了我Error in do.call(c, x) : 'what' must be a function or character string...
cbind() 与函数c() 不同,虽然这也有效,但它给出了不同的结果。
lapply() 是一个类似地图的函数。 do.call() 不同。它用于将参数以列表形式传递给函数,而不是枚举它们。例如,
> do.call("+",list(4,5))
[1] 9
【讨论】:
lapply 将函数应用于列表,do.call 调用带有参数列表的函数。这对我来说似乎有很大的不同......
举个例子:
X <- list(1:3,4:6,7:9)
使用 lapply,您可以像这样获得列表中每个元素的平均值:
> lapply(X,mean)
[[1]]
[1] 2
[[2]]
[1] 5
[[3]]
[1] 8
do.call 给出一个错误,因为 mean 期望参数“trim”为 1。
另一方面,rbind 按行绑定所有参数。所以要按行绑定 X,你可以这样做:
> do.call(rbind,X)
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
[3,] 7 8 9
如果您使用lapply,R 会将rbind 应用到列表的每个元素,给您这个废话:
> lapply(X,rbind)
[[1]]
[,1] [,2] [,3]
[1,] 1 2 3
[[2]]
[,1] [,2] [,3]
[1,] 4 5 6
[[3]]
[,1] [,2] [,3]
[1,] 7 8 9
要拥有类似 Map 的东西,您需要 ?mapply,这是完全不同的东西。要获得例如 X 中每个元素的平均值,但使用不同的修剪,您可以使用:
> mapply(mean,X,trim=c(0,0.5,0.1))
[1] 2 5 8
【讨论】: