Создать план рабочего процесса для всех комбинаций входов в 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()
функция, которая делает это.
- Файл справки и примеры: https://ropensci.github.io/drake/reference/map_plan.html
- Раздел в руководстве: https://ropenscilabs.github.io/drake-manual/plans.html
- Более практичный пример: https://ropenscilabs.github.io/drake-manual/gsp.html
Оригинальный пост
Извините, я опоздал на эту тему. Пару месяцев назад я добавил в руководство раздел о настраиваемом метапрограммировании, чтобы охватить ситуации, подобные той, которую вы подняли. В примере есть одно решение, использующее rlang
/ Tidyeval и эквивалентное решение с использованием as.call()
создавать вызовы функций.
Теперь, когда я думаю об этом, этот вариант использования достаточно общий, так что я думаю, что должно быть просто map_plan()
Функция, чтобы построить план для вас. Я буду работать над этим.
Кстати, command
Столбец в вашем плане может быть столбцом списка языковых объектов, а не символьным вектором, но вам нужен символьный столбец, чтобы использовать шаблонные шаблоны.