当前位置: 首页 > 知识库问答 >
问题:

为什么要用purrr::map而不是lapply?

倪灿
2023-03-14

我有什么理由使用

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

而不是

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

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

那么,对于如此简单的情况,有什么理由让我考虑切换到< code>purrr::map呢?我在这里不是问你喜欢或不喜欢purrr提供的语法和其他功能。,但严格来说是关于< code>purrr::map与< code>lapply的比较,假设使用标准评估,即< code>map(

共有3个答案

弘志勇
2023-03-14

如果我们不考虑品味(否则这个问题应该结束)或语法一致性、风格等方面,答案是否定的,没有特殊的理由使用< code>map而不是< code>lapply或apply系列的其他变体,如更严格的< code>vapply。

PS:对于那些无端投下票的人,只要记住OP写道:

我在这里并不是问你喜欢或不喜欢purrr等提供的语法、其他功能,而是严格地比较purrr::map与lapply假设使用标准评估

如果你不考虑语法或purrr的其他功能,那么使用map就没有特殊的理由。我自己使用呼噜声,我对哈德利的答案很好,但具有讽刺意味的是,它忽略了OP事先声明他没有问的事情。

赖浩荡
2023-03-14

提取列表的第二个元素

map(list, 2)  

正如普里维@F所指出的,这与以下情况相同:

map(list, function(x) x[[2]])

使用lapplication

lapply(list, 2) # doesn't work

我们需要传递一个匿名函数。。。

lapply(list, function(x) x[[2]])  # now it works

...或者正如@RichScriven指出的,我们将< code>[[作为参数传递给< code>lapply

lapply(list, `[[`, 2)  # a bit more simple syntantically

因此,如果您发现自己正在使用lapply将函数应用到许多列表中,并且厌倦了定义自定义函数或编写匿名函数,那么方便是支持purrr的原因之一。

  • map_chr()
  • map_lgl()
  • map_int()
  • map_dbl()
  • map_df()

这些特定于类型的映射函数中的每一个都返回一个向量,而不是map()lapplication()返回的列表。如果您正在处理嵌套的向量列表,您可以使用这些特定于类型的映射函数直接提取向量,并将向量直接强制转换为int、dbl、chr向量。基本R版本类似于as.numeric(sapplication(…))as.character(sapplication(…))等。

<代码>地图_

正如 Privé @F指出的那样,使用 purrr 的便利功能会稍微减慢处理速度。让我们对我上面介绍的4个案例中的每一个进行比赛。

# devtools::install_github("jennybc/repurrrsive")
library(repurrrsive)
library(purrr)
library(microbenchmark)
library(ggplot2)

mbm <- microbenchmark(
  lapply       = lapply(got_chars[1:4], function(x) x[[2]]),
  lapply_2     = lapply(got_chars[1:4], `[[`, 2),
  map_shortcut = map(got_chars[1:4], 2),
  map          = map(got_chars[1:4], function(x) x[[2]]),
  times        = 100
)
autoplot(mbm)

获胜者是。。。。

lapply(list, `[[`, 2)

总而言之,如果原始速度是你所追求的:基础::拉普利(尽管它没有那么快)

为了简单的语法和表达:purrr::map

这篇优秀的< code>purrr教程强调了使用< code>purrr时不必显式写出匿名函数的便利性,以及特定于类型的< code>map函数的好处。

漆雕亮
2023-03-14

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

>

  • ~.1相当于函数(x)x 1>)

    < code>list("x ",1)等价于< code > function(x)x[[" x "]][[1]]。这些助手比< code>[[ - see ?详情请点击。对于数据矩形化,< code >。default参数特别有用。

    但大多数时候,您没有使用单个*apply()/map()函数,而是使用了一组函数,purrr的优点是函数之间的一致性更强。例如:

    >

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

    使用vapplication()sapplication()mapplication(),您可以选择使用USE.NAMES=FALSE来抑制输出上的名称;但是lapplication()没有这个参数。

    没有一致的方法将一致的参数传递给mapper函数。大多数函数使用,但mapplication()使用MoreArgs(您希望将其称为MORE.ARGS),而Map()Filter()Reduce()希望您创建一个新的匿名函数。在map函数中,常量参数总是位于函数名称之后。

    几乎每个 purrr 函数都是类型稳定的:您可以仅从函数名称预测输出类型。对于 sapply()映射 ()而言,情况并非如此。是的,有 vapply();但是没有等效的映射()

    你可能会认为所有这些小的区别都不重要(就像有些人认为stringr相对于基本R正则表达式没有优势一样),但根据我的经验,它们在编程时会引起不必要的摩擦(不同的论证顺序总是用来绊倒我),它们使函数式编程技术更难学习,因为除了大想法, 你还必须学习一堆偶然的细节。

    Purrr还填充了基础R中缺少的一些方便的贴图变体:

    >

  • 修改()使用[[

    map2() 允许您同时映射 xy。这使得表达像map2(模型,数据集,预测)这样的想法变得更加容易。

    imap()允许您同时映射x及其索引(名称或位置)。这使得(例如)加载目录中的所有csv文件变得容易,并为每个文件添加一个文件名列。

    dir("\\.csv$") %>%
      set_names() %>%
      map(read.csv) %>%
      imap(~ transform(.x, filename = .y))
    

    walk()不可见地返回其输入;当您为函数的副作用(即将文件写入磁盘)调用函数时,它非常有用。

    更不用说像< code>safely()和< code>partial()这样的其他助手了。

    就我个人而言,我发现当我使用purrr时,我可以用更少的摩擦和更容易的方式编写函数代码;它减少了构思和实施之间的差距。但您的里程数可能会有所不同;没有必要使用purrr,除非它确实对你有帮助。

    是的,map()略慢于lapply()。但是,使用map()lapply()的成本是由您映射的内容决定的,而不是执行循环的开销。下面的微基准表明,与lapply()相比,map()的成本约为每个元素40纳秒,这似乎不太可能对大多数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
    

  •  类似资料:
    • 本文向大家介绍为什么要用 redis 而不用 map/guava 做缓存?相关面试题,主要包含被问及为什么要用 redis 而不用 map/guava 做缓存?时的应答技巧和注意事项,需要的朋友参考一下 缓存分为本地缓存和分布式缓存。以 Java 为例,使用自带的 map 或者 guava 实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着 jvm 的销毁而结束,并且在多实例的情况下,每个

    • 问题内容: 我不确定为什么列出项目时为什么需要使用ul-li而不是简单地使用div。我可以使两者看起来完全一样,因此与创建div相比,创建无序列表的功能优势在哪里? 问题答案: 为了语义正确。HTML具有表达事物列表的功能,它可以帮助Google机器人,屏幕阅读器以及所有不仅仅关心网站外观的用户更好地了解您的内容。

    • 问题内容: 的类是代表一地图,其中键和值都是字符串。这是因为对象用于读取文件,即文本文件。 那么,为什么他们在Java 5中不对此类进行改造以实现呢? 该javadoc的状态: 因为Properties是从Hashtable继承的,所以put和putAll方法可以应用于Properties对象。强烈建议不要使用它们,因为它们允许调用方插入键或值不是字符串的条目。应该改用setProperty方法。

    • 问题内容: 目前使用jQuery,当我需要在发生点击时做一些事情时,我会像这样… 我正在看别人在项目上有的代码,他们这样做是… 请注意,就我所知,它似乎在做相同的事情,除了它们使用的是live()函数(现在已弃用并且jQuery文档说要使用live()函数),但是无论哪种方式,为什么要使用live / on()而不是我的第一个示例? 问题答案: 因为您可能具有动态生成的元素(例如,来自AJAX调用

    • 问题内容: 在selenium.webdriver.common.by中使用By代替常规的find_element_by _…方法的目的和好处是什么?例如: vs: 问题答案: 据documentatio ñ 似乎是一种“ 私人 所使用的”法的方法和还可以使用页面对象 因此,使用Page Object模式是您可能需要+ 而不是的原因。 例如,您有一些包含元素值的变量 然后用它来定位元素为 如果由于

    • 问题内容: 我不明白为什么很少有导入包在“ java”后面附加“ x”。是什么原因?难道就和其他人一样吗? 问题答案: Swing最初是Java的扩展-可单独下载的库。它成为Java 1.2中“主要” JRE的一部分。一个单独的库声称拥有java。*包,这很奇怪,因此是目前的情况。还有许多其他扩展都有类似的故事。 在Swing的维基百科的文章有其历史提供更多的信息。