gpt4 book ai didi

r - 为什么使用 purrr::map 而不是 lapply?

转载 作者:行者123 更新时间:2023-12-03 04:20:59 24 4
gpt4 key购买 nike

我有什么理由应该使用

map(<list-like-object>, function(x) <do stuff>)

而不是

lapply(<list-like-object>, function(x) <do stuff>)

输出应该是相同的,我所做的基准测试似乎表明 lapply稍微快一些(应该是 map 需要评估所有非标准评估输入)。

那么,对于如此简单的情况,我是否应该考虑切换到purrr::map? ?我在这里并不是询问一个人对 purrr 等提供的语法、其他功能的喜欢或不喜欢,而是严格询问 purrr::map 的比较。与 lapply假设使用标准评估,即 map(<list-like-object>, function(x) <do stuff>)purrr::map有什么好处吗?在性能、异常处理等方面有什么?下面的评论表明事实并非如此,但也许有人可以详细说明一下?

最佳答案

如果您在 purrr 中使用的唯一函数是 map() ,那么不,优势并不明显。正如 Rich Pauloo 指出的那样,主要优势map()是允许您编写紧凑的帮助程序常见特殊情况的代码:

  • ~ . + 1相当于 function(x) x + 1 (以及 R-4.1 及更高版本中的 \(x) x + 1)

  • list("x", 1)相当于 function(x) x[["x"]][[1]] 。这些助手比 [[ 更通用一些- 请参阅?pluck了解详情。对于 datarectangling , 这 .default论证特别有帮助。

但大多数时候您不使用单个 *apply()/map()函数,你使用了一堆它们,而 purrr 的优点是功能之间具有更大的一致性。例如:

  • lapply() 的第一个参数是数据;第一个参数 mapply()是函数。所有映射函数的第一个参数始终是数据。

  • vapply() , sapply() ,和mapply()你可以选择使用 USE.NAMES = FALSE 抑制输出中的名称;但 lapply()没有这个论据。

  • 没有一致的方法将一致的参数传递给映射器功能。大多数函数使用 ...但是mapply()用途 MoreArgs (您希望将其称为 MORE.ARGS ),并且 Map() , Filter()Reduce()期待你创造一个新的匿名函数。在映射函数中,常量参数总是出现在函数名称之后。

  • 几乎每个 purrr 函数都是类型稳定的:您可以预测输出类型仅来自函数名称。这不适用于 sapply()mapply() 。是的,有vapply() ;但没有相当于 mapply() .

您可能认为所有这些细微差别都不重要(正如有些人认为 stringr 没有任何优势基本 R 正则表达式),但根据我的经验,它们会导致不必要的编程时的摩擦(总是使用不同的参数顺序绊倒我),并且它们使函数式编程技术更难实现学习,因为除了伟大的想法之外,你还必须学习很多东西附带细节。

Purrr 还填充了一些基本 R 中没有的方便的 map 变体:

  • modify()使用 [[<- 保留数据类型修改“在与 _if 变体结合使用,这允许(IMO漂亮)代码如 modify_if(df, is.factor, as.character)

  • map2()允许您同时映射 xy 。这可以更轻松地表达想法,例如 map2(models, datasets, predict)

  • imap()允许您同时映射 x及其指数(姓名或职位)。这使得加载所有内容变得容易(例如) csv目录中的文件,添加 filename每个列。

    dir("\\.csv$") %>%
    set_names() %>%
    map(read.csv) %>%
    imap(~ transform(.x, filename = .y))
  • walk()不可见地返回其输入;当你调用函数的副作用(即将文件写入磁盘)。

更不用说像 safely() 这样的其他助手了和partial() .

就我个人而言,我发现当我使用purrr时,我可以编写函数式代码摩擦更小,更轻松;它减少了之间的差距提出一个想法并实现它。但您的里程可能会有所不同;没有必要使用 purrr ,除非它确实对您有帮助。

微基准测试

是的,map()lapply() 稍慢。但使用成本 map()lapply()由您所映射的内容驱动,而不是开销执行循环。下面的微基准表明成本的map()lapply()相比每个元素大约 40 ns,其中似乎不太可能对大多数 R 代码产生重大影响。

library(purrr)
n <- 1e4
x <- 1:n
f <- function(x) NULL

mb <- microbenchmark::microbenchmark(
lapply = lapply(x, f),
map = map(x, f)
)
summary(mb, unit = "ns")$median / n
#> [1] 490.343 546.880

关于r - 为什么使用 purrr::map 而不是 lapply?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45101045/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com