目标
我正在尝试创建一个创建自定义交叉表(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
什么行不通
我希望能够使用此函数自动为不同的rows
,cols
和vals
生成不同的交叉表,例如使用for循环或其中一个map
函数(tidyverse等效于基础apply
函数)。换句话说,我希望能够做到这样的事情:
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]])
}
}
对于rows
和cols
我看到有些人使用group_by_at
,但这仍然无法解决vals
的问题。
我的问题
map
/ apply
进行调用时)?enquo
和朋友)使其工作太困难,那么解决这个问题的“基础”方法是什么?答案 0 :(得分:0)
一个选项是转换&#39; expr&#39;在quouts中然后在循环中,使用!!
评估参数以及将字符向量(&#39; colVars&#39;)转换为sym
(&#39; symbol&#39;)< / p>
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