我希望使用furrr包而不是purrr包来并行运行以下函数。
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等效项时,我得到了一个错误。
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)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“作为全局变量,但找不到它,因此出现错误。
当我只是将变量名插入到调用中时,它可以工作,但是现在该函数不再使用任何变量名:
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提供名称,但似乎都不起作用。有没有办法让这件事起作用呢?我的实际函数要复杂得多,但我假设原理是相同的。如果有人能帮上忙就太好了!
发布于 2020-09-22 16:58:39
future尝试自动确定您在代码中使用的全局变量。由于整齐的计算,它识别了a和b,但没有找到它们。您可以使用future_options(globals = FALSE)禁用此设置。
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发布于 2020-09-22 20:03:22
在最低级别,这似乎是globals包的一个错误,furrr使用该包查找需要导出到工作程序的全局变量。我已经在https://github.com/HenrikBengtsson/globals/issues/65上报了这个bug
这个问题与NSE (非标准评估)以及全局变量“寻找”全局变量的位置有关,并且可以仅使用全局变量和基数R来重现。使用全局变量0.13.0,我得到以下结果:
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'错误消息有点不同,但我相当确定这是相同的潜在问题。
奇怪的是,当列被硬编码时,没有发生错误,但我们仍然延迟计算。也就是说,这是有效的,但结果相当长,所以我不会显示输出:
library(globals)
fn <- function() {
expr <- quote(cyl)
eval(expr, envir = mtcars)
}
fn()
expr <- quote(fn())
globalsOf(expr)发布于 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函数中强制计算它们来解决这个问题。提前拆除它们会将var1和var2变成可以运往工人手中的对象。
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(),但在一些非常罕见的情况下,需要分离解除/强制。
https://stackoverflow.com/questions/64006043
复制相似问题