【问题标题】:What's the difference between lapply and do.call?lapply 和 do.call 有什么区别?
【发布时间】:2012-06-03 19:55:33
【问题描述】:

我最近在学习 R,被两个函数弄糊涂了:lapplydo.call。看起来它们只是类似于 Lisp 中的map 函数。但是为什么会有两个名称如此不同的函数呢?为什么 R 不直接使用名为 map 的函数?

【问题讨论】:

    标签: r functional-programming


    【解决方案1】:

    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)
    

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

        两者的区别是:

        lapply(1:n,function,parameters)
        

        => 这发送 1, 参数到函数 => 这将 2, 参数发送给函数 等等

        do.call 
        

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

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

        【讨论】:

          【解决方案4】:

          用最简单的话来说:

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

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

            李>

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

          【讨论】:

            【解决方案5】:

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

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

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

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


            1. Mapmapply 的包装
            2. lapplymapply 的特例
            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" 
            

            【讨论】:

            • 其实我发现do.call和Lisp中的apply差不多
            • 最后一个例子不应该是do.call(cbind, x),当前版本给了我Error in do.call(c, x) : 'what' must be a function or character string...
            • @snoram 这个例子仍然有效。函数cbind() 与函数c() 不同,虽然这也有效,但它给出了不同的结果。
            【解决方案6】:

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

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

            【讨论】:

              【解决方案7】:

              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
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2010-10-02
                • 2011-12-12
                • 2010-09-16
                • 2012-03-14
                • 2012-02-06
                • 2011-02-25
                • 2011-11-22
                相关资源
                最近更新 更多