为 Drake 中的所有输入组合生成工作流程计划?
Generate workflow plan for all combinations of inputs in Drake?
我正在尝试创建一个工作流计划,该计划将为 my_dataset
中的所有输入组合 运行 一些功能 my_function(x, y)
,但我不知道如何生成命令对于 drake 的工作流程,无需使用粘贴。
考虑:
library(drake)
library(dplyr)
A <- 'apple'
B <- 'banana'
C <- 'carrot'
my_function <- function(x, y)
paste(x, y, sep='|IT WORKS|')
my_function(A, B)
combos <- combn(c('A', 'B', 'C'), 2) %>%
t() %>%
as_data_frame()
targets <- apply(combos, 1, paste, collapse = '_')
commands <- paste0('my_function(', apply(combos, 1, paste, collapse = ', '), ')')
my_plan <- data_frame(target = targets, command = commands)
make(my_plan)
输出:
> my_plan
# A tibble: 3 x 2
target command
<chr> <chr>
1 A_B my_function(A, B)
2 A_C my_function(A, C)
3 B_C my_function(B, C)
以上代码有效,但我使用 paste0 生成函数调用。我认为这不是最优的,而且扩展性很差。有没有更好的方法来生成这些计划?这可能不是一个 drake 问题,而是一个 rlang
问题。
免责声明:此答案说明了如何使用 rlang
框架编写表达式。但是,drake
需要命令作为字符串,因此最终的表达式需要转换为字符串。
我们首先使用 quote
捕获 A
、B
和 C
作为符号,然后使用您已有的代码计算所有可能的成对组合:
CB <- combn( list(quote(A), quote(B), quote(C)), 2 ) %>%
t() %>% as_data_frame()
# # A tibble: 3 x 2
# V1 V2
# <list> <list>
# 1 <symbol> <symbol>
# 2 <symbol> <symbol>
# 3 <symbol> <symbol>
我们现在可以使用purrr::map2
来并行遍历两列并组成我们的表达式:
CMDs <- purrr::map2( CB$V1, CB$V2, ~rlang::expr( my_function((!!.x), (!!.y)) ) )
# [[1]]
# my_function(A, B)
# [[2]]
# my_function(A, C)
# [[3]]
# my_function(B, C)
如上所述,drake
需要字符串,因此我们必须将表达式转换为:
commands <- purrr::map_chr( CMDs, rlang::quo_name )
# [1] "my_function(A, B)" "my_function(A, C)" "my_function(B, C)"
您的其余代码应该像以前一样工作。
最终,由您决定表达式算术还是字符串算术对您的应用程序更有效/更易读。另外要提到的一件事是 stringr
包,它可能使字符串运算更容易进行。
编辑
drake
现在有一个 map_plan()
函数可以做到这一点。
- 帮助文件和示例:https://ropensci.github.io/drake/reference/map_plan.html
- 手册中的部分:https://ropenscilabs.github.io/drake-manual/plans.html#map_plan
- 更实际的例子:https://ropenscilabs.github.io/drake-manual/gsp.html
原版post
抱歉,我来晚了。几个月前,我在手册中的 custom metaprogramming 上添加了一节,以涵盖您提出的情况。在示例中,有一个解决方案使用 rlang
/tidyeval 和一个等效解决方案使用 as.call()
创建函数调用。
现在我想到了,这个用例足够通用,我认为应该有一个简单的 map_plan()
函数来为您构建计划。我会努力的。
顺便说一句,你计划中的command
列可以是语言对象的列表列而不是字符向量,但你需要一个字符列才能使用wildcard templating。
我正在尝试创建一个工作流计划,该计划将为 my_dataset
中的所有输入组合 运行 一些功能 my_function(x, y)
,但我不知道如何生成命令对于 drake 的工作流程,无需使用粘贴。
考虑:
library(drake)
library(dplyr)
A <- 'apple'
B <- 'banana'
C <- 'carrot'
my_function <- function(x, y)
paste(x, y, sep='|IT WORKS|')
my_function(A, B)
combos <- combn(c('A', 'B', 'C'), 2) %>%
t() %>%
as_data_frame()
targets <- apply(combos, 1, paste, collapse = '_')
commands <- paste0('my_function(', apply(combos, 1, paste, collapse = ', '), ')')
my_plan <- data_frame(target = targets, command = commands)
make(my_plan)
输出:
> my_plan
# A tibble: 3 x 2
target command
<chr> <chr>
1 A_B my_function(A, B)
2 A_C my_function(A, C)
3 B_C my_function(B, C)
以上代码有效,但我使用 paste0 生成函数调用。我认为这不是最优的,而且扩展性很差。有没有更好的方法来生成这些计划?这可能不是一个 drake 问题,而是一个 rlang
问题。
免责声明:此答案说明了如何使用 rlang
框架编写表达式。但是,drake
需要命令作为字符串,因此最终的表达式需要转换为字符串。
我们首先使用 quote
捕获 A
、B
和 C
作为符号,然后使用您已有的代码计算所有可能的成对组合:
CB <- combn( list(quote(A), quote(B), quote(C)), 2 ) %>%
t() %>% as_data_frame()
# # A tibble: 3 x 2
# V1 V2
# <list> <list>
# 1 <symbol> <symbol>
# 2 <symbol> <symbol>
# 3 <symbol> <symbol>
我们现在可以使用purrr::map2
来并行遍历两列并组成我们的表达式:
CMDs <- purrr::map2( CB$V1, CB$V2, ~rlang::expr( my_function((!!.x), (!!.y)) ) )
# [[1]]
# my_function(A, B)
# [[2]]
# my_function(A, C)
# [[3]]
# my_function(B, C)
如上所述,drake
需要字符串,因此我们必须将表达式转换为:
commands <- purrr::map_chr( CMDs, rlang::quo_name )
# [1] "my_function(A, B)" "my_function(A, C)" "my_function(B, C)"
您的其余代码应该像以前一样工作。
最终,由您决定表达式算术还是字符串算术对您的应用程序更有效/更易读。另外要提到的一件事是 stringr
包,它可能使字符串运算更容易进行。
编辑
drake
现在有一个 map_plan()
函数可以做到这一点。
- 帮助文件和示例:https://ropensci.github.io/drake/reference/map_plan.html
- 手册中的部分:https://ropenscilabs.github.io/drake-manual/plans.html#map_plan
- 更实际的例子:https://ropenscilabs.github.io/drake-manual/gsp.html
原版post
抱歉,我来晚了。几个月前,我在手册中的 custom metaprogramming 上添加了一节,以涵盖您提出的情况。在示例中,有一个解决方案使用 rlang
/tidyeval 和一个等效解决方案使用 as.call()
创建函数调用。
现在我想到了,这个用例足够通用,我认为应该有一个简单的 map_plan()
函数来为您构建计划。我会努力的。
顺便说一句,你计划中的command
列可以是语言对象的列表列而不是字符向量,但你需要一个字符列才能使用wildcard templating。