在 dplyr 中使用 "get"

Use of "get" in dplyr

背景是我有一些遗留代码在几个地方使用 plyr,直到几天前,plyr 还没有更新以使其与 R 3.5 一起使用。我认为这是对 plyr 支持减少的一个信号,因此我正在研究将 plyr 命令更改为 dplyr。遗留代码中的 ddply 命令涉及一些 "get" 命令来引用其名称包含在变量中的列。直接翻译将涉及以下类型的代码(一个人为的例子,但它说明了这一点)。它似乎有效,并使其最接近原始代码,但是这样做有什么陷阱吗?我的印象是这不是制造商认可的使用 dplyr 编程的方式!
示例代码:

library("dplyr")
testFunction <- function(dataset, groupcol, varcol){
  summaryTable <- dataset %>% 
    group_by(get(groupcol)) %>%
    summarise(mean_var = mean(get(varcol)),
              sd_var = sd(get(varcol)))
  return(summaryTable)
}
testGroup <- "cyl"
testVar <- "mpg"
testFunction(mtcars, testGroup, testVar)

作为恐龙,我很想从 plyr 转换回 base-R(看不到 "get"s),例如类似于:

fossilFunction <- function(dataset, groupcol, varcol){
  z <- by(dataset, dataset[ , testGroup], function(x){
    c(mean_var = mean(x[ , varcol]), 
      sd_var = sd(x[ , varcol]))
  })
  z <- do.call(rbind, z)
  data.frame(rownames(z), z, row.names = NULL)
}
testGroup <- "cyl"
testVar <- "mpg"
fossilFunction(mtcars, testGroup, testVar)

在这种情况下,速度不是问题。但是,必须努力向前看,而不是向后看...

我们可以使用 sym 将其转换为 symbol 如果我们传递一个字符串变量然后用 !!

求值
testFunction <- function(dataset, groupcol, varcol){

varcol <- rlang::sym(varcol)
 dataset %>% 
    group_by(!! rlang::sym(groupcol)) %>%
    summarise(mean_var = mean(!! varcol),
          sd_var = sd(!! varcol))

 }
testFunction(mtcars, testGroup, testVar)
# A tibble: 3 x 3
#    cyl mean_var sd_var
#  <dbl>    <dbl>  <dbl>
#1     4     26.7   4.51
#2     6     19.7   1.45
#3     8     15.1   2.56

或者不使用rlang,我们也可以将字符串传入group_by_atsummarise_at

testFunction <- function(dataset, groupcol, varcol){
 dataset %>% 
    group_by_at(groupcol)%>%
    summarise_at(vars(varcol),  funs(mean, sd))


 }

testFunction(mtcars, testGroup, testVar)

dplyr 的最新版本允许使用 bang-bang 运算符 (!!) 将变量插入到函数调用中。应避免使用 get() 函数。您可以通过以下方式修复您的功能

testFunction <- function(dataset, groupcol, varcol){
  groupcol <- as.name(groupcol)
  varcol <- as.name(varcol)
  summaryTable <- dataset %>% 
    group_by(!!groupcol) %>%
    summarise(mean_var = mean(!!varcol),
              sd_var = sd(!!varcol))
  return(summaryTable)
}
testGroup <- "cyl"
testVar <- "mpg"
testFunction(mtcars, testGroup, testVar)

有关详细信息,请参阅 programming with dplyr vignette

就我个人而言,我反对这里的一些正统观念,我只是在某些情况下使用 get

testFunction <- function(dataset, groupcol, varcol){
  dataset %>% 
    group_by(get(groupcol)) %>%
    summarise(mean_var = mean(get(varcol)),
              sd_var = sd(get(varcol)))
}

或者,我在 ..data 对象上使用双括号 [[

testFunction <- function(dataset, groupcol, varcol){
  dataset %>% 
    group_by(.data[[groupcol]]) %>%
    summarise(mean_var = mean(.data[[varcol]]),
              sd_var = sd(.data[[varcol]]))
}

我发现 get(x)!!as.name(x)!!rlang::sym(x) 更简单直观多年来,base 命名空间中的内置函数可能会成为我在接下来几年中求助的对象。