【问题标题】:Use of "get" in dplyr在 dplyr 中使用“get”
【发布时间】:2018-06-18 16:18:19
【问题描述】:

背景是我有一些遗留代码在一些地方使用 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”),例如类似:

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)

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

【问题讨论】:

    标签: r dplyr plyr


    【解决方案1】:

    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 函数?只是教条,还是有功能原因?我想 bang-bang 比 get 短 3 个字符!
    • @Knackiedoo 我想这可能更像是一个风格指南推荐。展示一个您得到错误结果的示例并不容易,但是当使用get() 时,并不总是很清楚您试图从哪里提取特定变量。通常,当我在 R 代码中看到 get()/assign() 时,它来自其他人从其他语言复制算法,而不是真正以“R 方式”做事。使用 dplyr 鼓励的符号和表达式(或 exprs)或 quosures 允许更灵活的代码,并且在使用比单个列名更复杂的表达式时表现更好。
    【解决方案2】:

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

    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)
    

    【讨论】:

    • 谢谢。 MrFlick 的答案类似,但在使用 bang bang 之前没有转换为符号,而且它似乎有效。是否有特定的原因或情况需要首先转换为符号? group_by_at 是一个很好的建议,但在实际情况下,summarise_at 不会削减它,因为摘要实际上比将单个函数应用于所有 varcol 复杂得多。
    • @Knackiedoo as.name 正在转换为符号 str(as.name(testGroup))# symbol cyl
    • 关于需要改成符号的条件,如果传递的参数是字符串。如果是不带引号的字符串,可以使用enquo 转换为quosure,然后执行!!
    • 好的,我明白了。我很确定 as.name 的理论编码问题不太可能成为问题,因此我将坚持使用基本函数而不是 sym。只是出于兴趣,我很好奇为什么“得到”会遭到如此反对。它少了一步,而且似乎有效。
    • 我只是指 sym 帮助“与 as.name() 相反,它们预先将字符串转换为本机编码”。我会相信你的话,因为 get 可能会出现环境/位置问题。只是想学习!
    【解决方案3】:

    就个人而言,我在这里反对一些正统观念,我只是在其中一些情况下使用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 命名空间可能会成为我的目标。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-23
      • 2020-11-21
      • 2017-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-26
      • 2017-12-23
      相关资源
      最近更新 更多