2

我正在尝试创建一个工作流程计划,该计划将为my_function(x, y)所有输入组合运行一些功能,my_dataset但对于如何在不使用粘贴的情况下为德雷克的工作流程生成命令而陷入困境。

考虑:

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 来生成函数调用。我认为这不是最佳的,而且扩展性很差。有没有更好的方法来生成这些计划?这可能不是一个德雷克问题,而是一个rlang问题。

4

2 回答 2

2

免责声明:此答案显示了如何使用rlang框架编写表达式。但是,drake需要将命令作为字符串,因此需要将最终表达式转换为字符串。

我们首先捕获ABC作为符号使用quote,然后使用您已有的代码计算所有可能的成对组合:

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包,它可能使字符串算术更令人愉快。

于 2018-08-27T15:54:42.160 回答
1

编辑

drake现在有一个map_plan()功能可以做到这一点。

原帖

对不起,我迟到了这个帖子。几个月前,我在手册中添加了一个关于自定义元编程的部分,以涵盖您提出的情况。在示例中,有一个使用/tidyeval 的解决方案和一个用于创建函数调用rlang的等效解决方案。as.call()

现在我想起来了,这个用例足够通用,我认为应该有一个简单的map_plan()函数来为您构建计划。我会努力的。

顺便说一句,command您计划中的列可以是语言对象的列表列而不是字符向量,但您需要一个字符列才能使用通配符模板

于 2018-10-12T17:12:50.593 回答