173

我最近在学习 R 并且对两个函数感到困惑:lapplydo.call. 看起来它们只是类似于mapLisp 中的函数。但是为什么会有两个名称如此不同的函数呢?为什么 R 不只使用一个名为 的函数map

4

7 回答 7

145

有一个函数调用Map,可能类似于其他语言中的 map:

  • lapply返回一个与 X 长度相同的列表,其中每个元素是对 X 的相应元素应用 FUN 的结果。

  • do.call从名称或函数以及要传递给它的参数列表构造并执行函数调用。

  • Map将函数应用于给定向量的相应元素...Map是一个简单的包装器,mapply它不会尝试简化结果,类似于 Common Lisp 的 mapcar(但是,参数被回收)。未来的版本可能允许对结果类型进行一些控制。


  1. Map是一个包装器mapply
  2. lapply是一个特例mapply
  3. 因此Maplapply在许多情况下将是相似的。

例如,这里是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将一个函数作为输入,并将其其他参数传递给该函数。它被广泛使用,例如,将列表组装成更简单的结构(通常使用rbindor cbind)。

例如:

x <- lapply(iris, class)
do.call(c, x)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
   "numeric"    "numeric"    "numeric"    "numeric"     "factor" 
于 2012-05-29T15:11:00.050 回答
69

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
于 2012-05-29T15:11:51.637 回答
45

lapply类似于mapdo.call不是。lapply将函数应用于列表的所有元素,do.call调用所有函数参数都在列表中的函数。所以对于一个n元素列表,lapplyn函数调用,并且do.call只有一个函数调用。所以do.calllapply. 希望这能澄清你的问题。

代码示例:

do.call(sum, list(c(1, 2, 4, 1, 2), na.rm = TRUE))

和:

lapply(c(1, 2, 4, 1, 2), function(x) x + 1)
于 2012-05-29T15:08:58.200 回答
32

用最简单的话来说:

  1. lapply()对列表中的每个元素应用一个给定的函数,因此会有多个函数调用。

  2. do.call()将给定函数应用于整个列表,因此只有一个函数调用。

最好的学习方法是使用 R 文档中的函数示例。

于 2013-10-29T11:48:39.930 回答
18

虽然已经有很多答案,但这里是我的例子供参考。假设我们有一个数据列表:

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 的返回类型实际上取决于执行的函数。

于 2015-06-02T16:52:10.760 回答
14

lapply()是一个类似地图的功能。do.call()是不同的。它用于将参数以列表形式传递给函数,而不是枚举它们。例如,

> do.call("+",list(4,5))
[1] 9
于 2012-05-29T15:12:10.410 回答
7

两者的区别是:

lapply(1:n,function,parameters)

=> 这将 1,参数发送给函数 => 这将 2,参数发送给函数,依此类推

do.call 

只需将 1…n 作为向量和参数发送到函数

所以在 apply 你有 n 个函数调用,在 do.call 你只有一个

于 2014-08-16T10:15:46.167 回答