Создать план рабочего процесса для всех комбинаций входов в Drake?

Я пытаюсь создать план рабочего процесса, который будет запускать некоторые функции 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 вопрос.

2 ответа

Решение

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Этот ответ показывает, как составлять выражения, используя rlang фреймворк. Тем не мение, drake ожидает команды как символьные строки, поэтому окончательные выражения необходимо будет преобразовать в строки.

Мы начинаем с захвата A, B а также C в качестве символов с использованием 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 пакет, который может сделать строковую арифметику более приятной для выполнения.

редактировать

drake теперь имеет map_plan() функция, которая делает это.

Оригинальный пост

Извините, я опоздал на эту тему. Пару месяцев назад я добавил в руководство раздел о настраиваемом метапрограммировании, чтобы охватить ситуации, подобные той, которую вы подняли. В примере есть одно решение, использующее rlang/ Tidyeval и эквивалентное решение с использованием as.call() создавать вызовы функций.

Теперь, когда я думаю об этом, этот вариант использования достаточно общий, так что я думаю, что должно быть просто map_plan() Функция, чтобы построить план для вас. Я буду работать над этим.

Кстати, command Столбец в вашем плане может быть столбцом списка языковых объектов, а не символьным вектором, но вам нужен символьный столбец, чтобы использовать шаблонные шаблоны.

Другие вопросы по тегам