【问题标题】:Programming Functions: NSE in DPLYR and PURRR编程功能:DPLYR 和 PURRR 中的 NSE
【发布时间】:2019-04-03 03:41:51
【问题描述】:

目前,当我尝试将函数包装在我多次使用的 dplyr 和 purrr 完成的一些计算时,我遇到了一些非标准评估问题。

我已阅读有关 NSE 的信息,并且认为我知道我的功能无法正常工作的地方 - 但是,我无法弄清楚为什么会这样。

例如,我想围绕以下计算包装一个函数,其中分组变量以及新变量的名称、使用的分类变量和均值的输入变量应该是动态的:

 Data <- Data %>%
  group_by(WeekBeforeRelease) %>%
  mutate(visitors_genreother_instr = map_dbl(Genre_Category, ~ mean(Visitors[Genre_Category != .x]))) %>%
  ungroup() %>%
  as.data.frame()

按照here 的描述,使用 NSE 将这个函数变成如下:

Function_Other <- function(ENDOGVAR, VARNAME, GROUP_MOVIE, GROUP_TIME){

  ENDOGVAR <- enquo(ENDOGVAR)
  VARNAME <- quo_name(enquo(VARNAME))
  GROUP_MOVIE <- enquo(GROUP_MOVIE)
  GROUP_TIME <- enquo(GROUP_TIME)

  Data <<- Data %>%
    group_by(!!GROUP_TIME) %>%
    mutate(!!VARNAME := map_dbl(!!GROUP_MOVIE, ~mean(!!ENDOGVAR[!!GROUP_MOVIE != .x]))) %>%
    ungroup() %>%
    as.data.frame()
}

但是,这似乎不能很好地处理平均值计算中带括号的子集。如果我将 !!ENDOGVAR 替换为访客,则一切正常且按预期进行。但是,它会产生以下错误:

Error in NextMethod("[") : object '.x' not found 

我很高兴能帮助我理解这个问题。

提前非常感谢!

回旋曲

【问题讨论】:

    标签: r tidyverse purrr nse


    【解决方案1】:

    我们可以将!! 包裹在大括号中以避免任何操作优先级,现在应该可以正常工作了

    library(tidyverse)
    Function_Other <- function(ENDOGVAR, VARNAME, GROUP_MOVIE, GROUP_TIME){
    
      ENDOGVAR <- enquo(ENDOGVAR)
      VARNAME <- quo_name(enquo(VARNAME))
      GROUP_MOVIE <- enquo(GROUP_MOVIE)
      GROUP_TIME <- enquo(GROUP_TIME)
    
      Data %>%
        group_by(!!GROUP_TIME) %>%
        mutate(!!VARNAME := map_dbl(!!GROUP_MOVIE, ~
               mean((!!ENDOGVAR)[(!!GROUP_MOVIE) != .x]))) %>%
        ungroup() %>%
        as.data.frame()
    
    }
    
    
    Data <- mtcars
    out <- Function_Other(mpg, newcol, am, gear)
    head(out, 3)
    #   mpg cyl disp  hp drat    wt  qsec vs am gear carb newcol
    #1 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4  21.05
    #2 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4  21.05
    #3 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1  21.05
    

    更新

    使用rlang 0.4.0(使用dplyr0.8.2 测试)我们还可以使用{{...}} 来代替、引用和取消引用。前面的函数可以写成

    Function_OtherN <- function(ENDOGVAR, VARNAME, GROUP_MOVIE, GROUP_TIME){  
    
    
      Data %>%
        group_by({{GROUP_TIME}}) %>%
        mutate({{VARNAME}} := map_dbl({{GROUP_MOVIE}}, ~
               mean({{ENDOGVAR}}[{{GROUP_MOVIE}} != .x]))) %>%
        ungroup() %>%
        as.data.frame()
    
    }
    
    
    out1 <- Function_OtherN(mpg, newcol, am, gear)
    

    -检查之前的输出

    identical(out1, out)
    [1] TRUE
    

    【讨论】:

    • Akrun,你是我的英雄 - 非常感谢,这解决了问题(和我的夜晚!)。关于为什么没有括号评估失败的任何想法?
    • @RondoBohrens 原因可能是操作优先级,因为在您创建一些逻辑表达式、子集等的地方发生了很多活动
    • @akrun 的解决方案非常有效,但是对于良好的编程实践应该指出两点(@akrun 肯定知道,但一些新读者可能不知道):1. 传递数据而不是使用全局可变数据。 2. 如果变量是从列表或 c() 绑定传递的,则传递不带引号的变量将不起作用。将它们作为字符串传递会更实际 - 在这种情况下,它们必须通过 'rlang::syms()` 进行转换(类似于 enquo)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    • 1970-01-01
    相关资源
    最近更新 更多