使用 Dplyr 编程:如何制作可在 for 循环中使用的函数?

Programming with Dplyr: How to make a function that can be used in a for loop?

目标

我正在尝试创建一个函数来创建自定义交叉 table (a.k.a.pivot table)。为此,我使用了 rlang 包,试图坚持 "dplyr" 编程方式。另见 http://dplyr.tidyverse.org/articles/programming.html.

函数

library(tidyverse)

crossTable <- function(
  df,
  rows,
  cols,
  vals
){

  quoRows = enquo(rows)
  quoCols = enquo(cols)
  quoVals = enquo(vals)

  result <-
    df %>%
    group_by(!!quoRows, !!quoCols) %>%
    summarize(
      values = !!quoVals
    ) %>%
    ungroup() %>%
    spread(!!quoCols, values)

}

有效方法

在全局环境中调用此函数有效。

a <- crossTable(mpg, manufacturer, cyl, mean(hwy))
a

什么不起作用

我希望能够使用此功能为不同的 rowscolsvals 自动生成不同的交叉 table,例如通过使用 for 循环或 map 函数之一(相当于基础 apply 函数的 tidyverse)。换句话说,我希望能够做这样的事情:

b <- list()

colVars <- c(cyl, class)

expr <- c(mean(hwy), mean(cty), median(hwy), median(cty))

for(i in seq_along(colVars)){

  for(j in seq_along(expr)){

    b[[i]][[j]] <- crossTable(mpg, manufacturer, colVars[[i]], expr[[j]])

  }

}

对于rowscols我看到有些人使用group_by_at,但这仍然没有解决vals的问题。

我的问题

一个选项是将 'expr' 转换为 quosures,然后在循环内,使用 !! 评估参数以及将字符向量 ('colVars') 转换为 sym ('symbol')

colVars <- c("cyl", "class")
b <- vector('list', length(colVars))
expr <- quos(mean(hwy), mean(cty), median(hwy), median(cty))
for(i in seq_along(colVars)){

  for(j in seq_along(expr)){

    b[[i]][[j]] <- crossTable(mpg, manufacturer, !!rlang::sym(colVars[i]), !! expr[[j]])

  }

}

-检查输出

identical(crossTable(mpg, manufacturer, cyl, mean(hwy)), b[[1]][[1]])
#[1] TRUE
identical(crossTable(mpg, manufacturer, cyl, mean(cty)), b[[1]][[2]])
#[1] TRUE
identical(crossTable(mpg, manufacturer, cyl, median(hwy)), b[[1]][[3]])
#[1] TRUE
identical(crossTable(mpg, manufacturer, cyl, median(cty)), b[[1]][[4]]) 
#[1] TRUE