Передача выражения в `MoreArgs` из`mapply`
Я занимаюсь программированием, используя dplyr
и мне интересно, как передать выражение как (MoreArgs
) аргумент к mapply
?
Рассмотрим простую функцию F
это подмножество data.frame
основанный на некоторых ids
и time_range
затем выводит сводную статистику на основе некоторого другого столбца x
,
require(dplyr)
F <- function(ids, time_range, df, date_column, x) {
date_column <- enquo(date_column)
x <- enquo(x)
df %>%
filter(person_id %chin% ids) %>%
filter(time_range[1] <= (!!date_column) & (!!date_column) <= time_range[2]) %>%
summarise(newvar = sum(!!x))
}
Мы можем составить пример данных, к которым мы можем применить нашу функцию F
,
person_ids <- lapply(1:2, function(i) sample(letters, size = 10))
time_ranges <- lapply(list(c("2014-01-01", "2014-12-31"),
c("2015-01-01", "2015-12-31")), as.Date)
require(data.table)
dt <- CJ(person_id = letters,
date_col = seq.Date(from = as.Date('2014-01-01'), to = as.Date('2015-12-31'), by = '1 day'))
dt[, z := rnorm(nrow(dt))] # The variable we will later sum over, i.e. apply F to.
Мы можем успешно применять нашу функцию к каждому из наших входов.
F(person_ids[[1]], time_ranges[[1]], dt, date_col, z)
F(person_ids[[2]], time_ranges[[2]], dt, date_col, z)
И поэтому, если бы я хотел, я мог бы написать простой цикл for, чтобы решить мою проблему. Но если мы попытаемся применить синтаксический сахар и обернуть все в mapply
мы получаем ошибку.
mapply(F, ids = person_ids, time_range = time_ranges, MoreArgs = list(df = dt, date_column = date_col, x = z))
# Error in mapply... object 'date_col' not found
1 ответ
В mapply
, MoreArgs
предоставляется в виде списка, но R пытается оценить элементы списка, вызывая ошибку. Как подсказывает @Gregor, вы можете quote
те MoreArgs
что мы не хотим оценивать сразу, предотвращая ошибку и позволяя функции продолжаться. Это можно сделать с помощью базы quote
или же dplyr
quo
:
mapply(F, person_ids, time_ranges, MoreArgs = list(dt, quote(date_col), quote(z)))
mapply(F, person_ids, time_ranges, MoreArgs = list(dt, quo(date_col), quo(z)))
Другой вариант заключается в использовании map2
от purrr
пакет, который является tidyverse
эквивалент mapply
с двумя входными векторами. tidyverse
функции настроены на работу с нестандартной оценкой, что позволяет избежать ошибок, с которыми вы получаете mapply
без необходимости приводить аргументы:
library(purrr)
map2(person_ids, time_ranges, F, dt, date_col, z)
[[1]] newvar 1 40.23419 [[2]] newvar 1 71.42327
В целом, вы можете использовать pmap
, который выполняет итерацию параллельно по любому количеству входных векторов:
pmap(list(person_ids, time_ranges), F, dt, date_col, z)