首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对毛发使用整洁的求值

对毛发使用整洁的求值
EN

Stack Overflow用户
提问于 2020-09-22 16:40:32
回答 3查看 221关注 0票数 2

我希望使用furrr包而不是purrr包来并行运行以下函数。

代码语言:javascript
复制
library(furrr)
library(tidyverse)

input <- list(element1 = tibble::tibble(a = c(1, 2), b = c(2, 2)),
              element2 = tibble::tibble(a = c(1, 2), b = c(4, 4))
)

multiplier <- function(data, var1, var2){
  purrr::map_df(.x = data,
                .f = ~ .x %>% 
                  dplyr::mutate(product = {{var1}} * {{var2}})
  )
}

multiplier(input, a, b)

但是,当我只是将它转换为furrr等效项时,我得到了一个错误。

代码语言:javascript
复制
multiplier_parallel <- function(data, var1, var2){
  furrr::future_map_dfr(.x = data,
                .f = ~ .x %>% 
                  dplyr::mutate(product = {{var1}} * {{var2}})
  )
}

future::plan(multiprocess)

multiplier_parallel(input, a, b)
代码语言:javascript
复制
Error in get(name, envir = env, inherits = FALSE) : 
Identified global objects via static code inspection (structure(function (..., .x = ..1, .y = ..2, . = 
..1); .x %>% dplyr::mutate(product = {; {; var1; }; } * {; {; var2; }; }), class = 
c("rlang_lambda_function", "function"))). Object 'a' not found 

我假设原因是future包查找要导出到工作程序的所有必要变量。在本例中,它查找列名"a“作为全局变量,但找不到它,因此出现错误。

当我只是将变量名插入到调用中时,它可以工作,但是现在该函数不再使用任何变量名:

代码语言:javascript
复制
multiplier_parallel <- function(data, var1, var2){
  furrr::future_map_dfr(.x = data,
                .f = ~ .x %>% 
                  dplyr::mutate(product = a * b)
  )
}

multiplier_parallel(input, a, b)

到目前为止,我尝试了几种方法,包括向.future_options提供名称,但似乎都不起作用。有没有办法让这件事起作用呢?我的实际函数要复杂得多,但我假设原理是相同的。如果有人能帮上忙就太好了!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-09-22 16:58:39

future尝试自动确定您在代码中使用的全局变量。由于整齐的计算,它识别了ab,但没有找到它们。您可以使用future_options(globals = FALSE)禁用此设置。

代码语言:javascript
复制
future::plan(future::multiprocess)

input <- list(element1 = tibble::tibble(a = c(1, 2), b = c(2, 2)),
              element2 = tibble::tibble(a = c(1, 2), b = c(4, 4))
)

multiplier_parallel <- function(data, var1, var2){
      furrr::future_map_dfr(.x = data,
                            .f = ~ .x %>% 
                                  dplyr::mutate(product = {{var1}} * {{var2}}),
                            .options = furrr::future_options(globals = FALSE)
      )
}

multiplier_parallel(input, a, b)
# A tibble: 4 x 3
      a     b product
  <dbl> <dbl>   <dbl>
1     1     2       2
2     2     2       4
3     1     4       4
4     2     4       8
票数 5
EN

Stack Overflow用户

发布于 2020-09-22 20:03:22

在最低级别,这似乎是globals包的一个错误,furrr使用该包查找需要导出到工作程序的全局变量。我已经在https://github.com/HenrikBengtsson/globals/issues/65上报了这个bug

这个问题与NSE (非标准评估)以及全局变量“寻找”全局变量的位置有关,并且可以仅使用全局变量和基数R来重现。使用全局变量0.13.0,我得到以下结果:

代码语言:javascript
复制
library(globals)

fn <- function(expr) {
  expr <- substitute(expr)
  eval(expr, envir = mtcars)
}

fn(cyl)
#>  [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4

expr <- quote(fn(cyl))

globalsOf(expr)
#> Error in globalsByName(names, envir = envir, mustExist = mustExist): Identified global objects via static code inspection (fn(cyl)). Failed to locate global object in the relevant environments: 'cyl'

错误消息有点不同,但我相当确定这是相同的潜在问题。

奇怪的是,当列被硬编码时,没有发生错误,但我们仍然延迟计算。也就是说,这是有效的,但结果相当长,所以我不会显示输出:

代码语言:javascript
复制
library(globals)

fn <- function() {
  expr <- quote(cyl)
  eval(expr, envir = mtcars)
}

fn()

expr <- quote(fn())

globalsOf(expr)
票数 2
EN

Stack Overflow用户

发布于 2020-09-22 20:35:15

啊,在我之前的回答中,我忘记了这是furrr的“常见陷阱”之一。前面的答案不一定是不正确的,并提供了一些额外的见解,所以我就不说了。有关更多信息,请参阅此帖子https://davisvaughan.github.io/furrr/articles/articles/gotchas.html#non-standard-evaluation-of-arguments

与purrr不同的是,使用furrr时,每个参数都必须提前评估一次,以便能够将其发送给工作人员。这意味着与使用NSE的参数有一些不同。实际上,您可以通过首先使用enquo()消除参数,然后使用!!在furrr函数中强制计算它们来解决这个问题。提前拆除它们会将var1var2变成可以运往工人手中的对象。

代码语言:javascript
复制
input <- list(
  element1 = tibble::tibble(a = c(1, 2), b = c(2, 2)),
  element2 = tibble::tibble(a = c(1, 2), b = c(4, 4))
)

multiplier_parallel <- function(data, var1, var2) {
  var1 <- rlang::enquo(var1)
  var2 <- rlang::enquo(var2)
  
  furrr::future_map_dfr(
    .x = data,
    .f = ~dplyr::mutate(.x, product = * var2)
  )
}

future::plan(future::multisession, workers = 2)

multiplier_parallel(input, a, b)
#> # A tibble: 4 x 3
#>       a     b product
#>   <dbl> <dbl>   <dbl>
#> 1     1     2       2
#> 2     2     2       4
#> 3     1     4       4
#> 4     2     4       8

请注意,我们通常鼓励使用{{ }}拥抱模式而不是!!enquo(),但在一些非常罕见的情况下,需要分离解除/强制。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64006043

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档