将表达式传递到 `mapply` 的 `MoreArgs`

Passing an expression into `MoreArgs` of `mapply`

我正在使用 dplyr 进行一些编程,并且很好奇如何将表达式作为(特别是 MoreArgs)参数传递给 mapply?

考虑一个简单的函数 F,它根据 idstime_rangedata.frame 进行子集化,然后根据其他列 [=] 输出汇总统计信息21=].

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

mapply 中,MoreArgs 作为列表提供,但 R 尝试计算列表元素,导致错误。正如@Gregor 所建议的,您可以 quote 我们不想立即评估的 MoreArgs ,防止错误并允许函数继续。这可以用 base quotedplyr 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)))

另一种选择是使用 purrr 包中的 map2,它是具有两个输入向量的 mapplytidyverse 等价物。 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)