lapply和do.call有什么区别?


143

我最近学习R和由两个功能感到困惑:lapplydo.call。似乎它们与mapLisp中的功能相似。但是,为什么有两个函数的名称如此不同?为什么R不只使用一个称为的函数map

Answers:


125

有一个叫做的函数Map,可能与其他语言的map类似:

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

  • 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将一个函数作为输入并将其其他参数溅到该函数上。例如,它广泛用于将列表组装成更简单的结构(通常使用rbindcbind)。

例如:

x <- lapply(iris, class)
do.call(c, x)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
   "numeric"    "numeric"    "numeric"    "numeric"     "factor" 

4
其实我发现do.call几乎一样apply在Lisp中
韩非日

那不是应该是do.call(cbind, x)当前版本的最后一个例子给了我Error in do.call(c, x) : 'what' must be a function or character string吗?
sindri_baldur

1
@snoram该示例仍然有效。该函数cbind()与函数有所不同c(),尽管它也可以工作,但结果却不同。
安德里

61

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 给出错误,因为平均值期望参数“ 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

34

lapply类似于mapdo.call不是。lapply将函数应用于列表的所有元素,do.call调用所有函数参数都在列表中的函数。因此,对于n元素列表,lapply具有n函数调用,并且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)

25

用最简单的话来说:

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

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

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


12

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

> do.call("+",list(4,5))
[1] 9

10

尽管答案很多,这里还是我的例子供参考。假设我们有一个数据列表:

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


5

两者之间的区别是:

lapply(1:n,function,parameters)

=>向功能发送1个参数=>向功能发送2个参数,依此类推

do.call 

只需发送1…n作为向量和参数即可

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.