purrr相对于apply系列的优势

13 浏览
0 Comments

purrr相对于apply系列的优势

有没有任何理由让我使用map(, function(x) )而不是lapply(, function(x) ),输出应该是一样的,我做的基准测试似乎表明lapply稍微快一点(这是因为map需要评估所有非标准评估的输入)。因此,对于这种简单情况,有没有任何理由让我考虑切换到purrr::map呢?我在这里询问的不是关于语法喜好或不喜好,purrr提供的其他功能等等,而仅仅是关于purrr::maplapply的比较,假设使用标准评估,即map(, function(x) )。在性能、异常处理等方面,purrr::map有什么优势吗?下面的评论表明没有,但也许有人可以详细解释一下?

0
0 Comments

在这段内容中,作者提出了一个关于使用`purrr`的`map`函数和`apply`系列函数(如`lapply`和`vapply`)的比较的问题。作者指出,如果不考虑个人口味、语法一致性和样式等方面,那么使用`map`而不是`lapply`或其他`apply`系列函数,如更严格的`vapply`,没有特殊的原因。

作者补充说,如果不考虑`purrr`的语法和其他功能,没有特殊的原因使用`map`。作者自己使用`purrr`并对Hadley的回答感到满意,但讽刺的是,他回答的内容恰好涉及到了作者最初明确表示不想问的内容。

接着,作者提到自己是因为一个同事的脚本中充满了`map`函数,而他想要使用`future.apply::future_lapply`或`furrr::future_map`。现在他知道可以安全地将一个替换为另一个了。

这段内容是关于使用`purrr`的`map`函数和`apply`系列函数的比较。作者问道是否有必要担心在`lapply`和`map`之间的一些差异,或者可以在它们之间更或多或少地互换使用。作者得到了答案,可以安全地替换它们。

0
0 Comments

purrr与apply家族的比较主要涉及便利性和速度两个方面。

1. purrr::map在语法上比lapply更方便

提取列表的第二个元素

map(list, 2)  

正如Privé指出的那样,这与以下代码是相同的:

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

使用lapply

lapply(list, 2) # 无法工作

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

lapply(list, function(x) x[[2]])  # 现在可以工作了

……或者如Privé所指出的,我们将[[作为参数传递给lapply

lapply(list, `[[`, 2)  # 语法上更简单一些

因此,如果发现自己使用lapply对许多列表应用函数,并且厌倦了定义自定义函数或编写匿名函数,便利性是偏好purrr的原因之一。

2. 类型特定的map函数简化了很多代码

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

这些类型特定的map函数中的每一个都返回一个向量,而不是map()和lapply()返回的列表。如果你处理嵌套的向量列表,你可以使用这些类型特定的map函数直接提取向量,并将向量直接转换为int、dbl、chr向量。基本的R版本可能看起来像as.numeric(sapply(...))as.character(sapply(...))等等。

map_函数还具有一个有用的特性,即如果它们不能返回所指定类型的原子向量,则会失败。当定义严格的控制流时,这是有用的,如果函数生成了错误的对象类型,你希望它失败。

3. 便利性之外,lapply比map稍微更快

使用purrr的便利函数,如Privé所指出的,会稍微减慢处理速度。让我们比较一下我上面提到的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)

enter image description here

冠军是....

lapply(list, `[[`, 2)

总之,如果追求原始速度,使用base::lapply(尽管它并不快多少)

对于简单的语法和可表达性,使用purrr::map

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

请注意,如果使用function(x) x[[2]]而不仅仅是2,它会更慢。所有这些额外的时间都是由于lapply不进行的检查而导致的。

你不需要使用匿名函数。[[是一个函数。你可以使用lapply(list, "[[", 3)

那是有道理的。这简化了使用lapply比purrr的语法。

as.numeric(sapply(...))是一种奇怪的做法。使用vapply:vapply(..., FUN.VALUE = numeric(1))。这是从apply函数返回向量的基本R方式,也强制执行类型(如果你的函数不返回正确的类型,会抛出错误)。这也比sapply/lapply性能更好,因为整个向量可以一次性分配。map_type的唯一额外优点是它对初学者更友好一点。

0
0 Comments

Purrr是一个R语言的包,它提供了一组函数,用于进行迭代运算和函数式编程。与R的apply家族函数相比,Purrr具有以下优点:

1. 代码紧凑:Purrr的map函数提供了一些辅助函数,可以用更紧凑的方式编写常见的特殊情况代码。

- 例如,使用`~ . + 1`可以代替`function(x) x + 1`。

- 使用`list("x", 1)`可以代替`function(x) x[["x"]][[1]]`。

- 这些辅助函数比`[[`更通用。

2. 一致性:Purrr的函数在参数和用法上更加一致。

- 所有map函数的第一个参数始终是数据,而不像lapply和mapply函数的参数顺序不一致。

- 使用vapply、sapply和mapply函数时,可以选择使用USE.NAMES = FALSE来取消输出的命名,而lapply函数没有这个参数。

- 没有一种一致的方式将参数传递给映射函数,大多数函数使用...,但mapply使用MoreArgs,而Map、Filter和Reduce函数需要创建一个新的匿名函数。在map函数中,常量参数始终在函数名称之后。

- 几乎每个purrr函数都是类型稳定的,可以从函数名称中预测输出类型,而sapply和mapply函数则不是。

3. 提供了一些有用的map变种函数,这些函数在基本的R语言中是缺失的。

- modify()函数通过使用[[<-对数据进行原地修改,从而保留了数据的类型。与_if变体一起使用,可以编写出优雅的代码,如modify_if(df, is.factor, as.character)。

- map2()函数允许同时对x和y进行映射,使得表达式如map2(models, datasets, predict)更容易表达。

- imap()函数允许同时对x和其索引(名称或位置)进行映射,可以方便地(例如)加载目录中的所有csv文件,并为每个文件添加一个filename列。

- walk()函数以不可见方式返回其输入,当需要调用一个函数来产生副作用时(例如将文件写入磁盘)很有用。

- 还有其他一些辅助函数,如safely()和partial()。

Purrr可以帮助我们更轻松地编写函数式的R代码,减少了编程时的摩擦和难度。虽然每个人的使用情况可能会有所不同,但除非真正有所帮助,否则没有必要使用Purrr。

此外,有人可能关心Purrr与apply家族函数的性能差异。实际上,根据微基准测试的结果,使用map()函数可能比使用lapply()函数稍慢,但这个差距很小,对大多数R代码来说不会有实质性的影响。

最后,还有一些读者提到了一些关于具体用法的问题和建议,如使用transform()函数的替代方案、对类型的特殊性的讨论以及对R中函数包数量的疑问。这些问题并不直接与Purrr的优点和apply家族函数的比较相关,因此可能需要在其他上下文中进行深入讨论。

0