【问题标题】:Unquote quosure outside quasiquotation context在 quasiquotation 上下文之外取消引用 quosure
【发布时间】:2019-10-29 06:04:55
【问题描述】:

我正在定义一个函数来获取回归模型的预测值,其中包含不同亚组(亚群)的调查数据。我使用了调查包中的 svyglm 函数。

我的问题涉及处理 svyglm 函数中的子集选项。由于它使用非标准评估,我理解这意味着它不会将列名作为字符串。我尝试只使用不带字符串的列名并引用(enquo)并取消引用它(!!)。但是,这两个选项都不起作用。我也玩过 ensym() 和 expr() 但没有得到任何结果。

数据和图书馆

library(dplyr)
library(survey)
library(srvyr)
library(purrr)
library(rlang)

mtcars <- read.table("https://forge.scilab.org/index.php/p/rdataset/source/file/master/csv/datasets/mtcars.csv",
                     sep=",", header=TRUE)

mtcars_cplx <- mtcars %>% as_survey_design(id = cyl, weights = qsec)

carb <- c(1:8)
cyl <- c(4:8)
new_data <- expand.grid(carb, cyl)
colnames(new_data) <- c("carb", "cyl")

有礼貌

功能与输入

subpop_pred <- function(formula, data, subpop, new_data) {
  
  subpop_quo <- enquo(subpop)
  subpop_txt <- data$variables %>% select(!!subpop_quo) %>% colnames()
  
  for(i in min(data$variables[subpop_txt]):max(data$variables[subpop_txt])){
    reg <- svyglm(formula, data, subset=!!subpop_quo==i)
    pred <- predict(reg, newdata=new_data)
    
    if(exists("reg_end")==TRUE){
      pred <- cbind(new_data, pred, confint(pred))
      pred[subpop_txt] <- i
      reg_end <- rbind(reg_end, pred)
    } else {
      reg_end <- cbind(new_data, pred, confint(pred))
      reg_end[subpop_txt] <- i
    }
  }
}

subpop_pred(mpg ~ carb + cyl + carb*cyl, 
            data=mtcars_cplx, 
            new_data=new_data,
            subpop=gear)

输出/错误

 Error: Base operators are not defined for quosures.
Do you need to unquote the quosure?

  # Bad:
  myquosure == rhs

  # Good:
  !!myquosure == rhs
Call `rlang::last_error()` to see a backtrace 
8. stop(cnd) 
7. abort(paste_line("Base operators are not defined for quosures.", 
    "Do you need to unquote the quosure?", "", "  # Bad:", bad, 
    "", "  # Good:", good, )) 
6. Ops.quosure(subpop_quo, i) 
5. eval(subset, model.frame(design), parent.frame()) 
4. eval(subset, model.frame(design), parent.frame()) 
3. svyglm.survey.design(formula, data, subset = !!subpop_quo == 
    i) 
2. svyglm(formula, data, subset = !!subpop_quo == i) 
1. subpop_pred(mpg ~ carb + cyl + carb * cyl, data = mtcars_cplx, 
    new_data = new_data, subpop = gear) 

无限制

功能与输入

subpop_pred <- function(formula, data, subpop, new_data) {
  
  subpop_quo <- enquo(subpop)
  subpop_txt <- data$variables %>% select(!!subpop_quo) %>% colnames()
  
  for(i in min(data$variables[subpop_txt]):max(data$variables[subpop_txt])){
    reg <- svyglm(formula, data, subset=subpop==i)
    pred <- predict(reg, newdata=new_data)
    
    if(exists("reg_end")==TRUE){
      pred <- cbind(new_data, pred, confint(pred))
      pred[subpop_txt] <- i
      reg_end <- rbind(reg_end, pred)
    } else {
      reg_end <- cbind(new_data, pred, confint(pred))
      reg_end[subpop_txt] <- i
    }
  }
}

subpop_pred(mpg ~ carb + cyl + carb*cyl, data=mtcars_cplx, new_data=new_data, subpop=gear)

输出

Error in eval(subset, model.frame(design), parent.frame()) : 
  object 'gear' not found 
5. eval(subset, model.frame(design), parent.frame()) 
4. eval(subset, model.frame(design), parent.frame()) 
3. svyglm.survey.design(formula, data, subset = subpop == i) 
2. svyglm(formula, data, subset = subpop == i) 
1. subpop_pred(mpg ~ carb + cyl + carb * cyl, data = mtcars_cplx, 
    new_data = new_data, subpop = gear) 

您知道如何使该功能发挥作用吗?

【问题讨论】:

  • 如何手动对函数中的数据集进行子集化并将其传递给svyglm()data 参数而不是使用subset 参数?您可以使用,例如,filter(),因为看起来您已经在使用 dplyr
  • 看起来subset 参数的工作方式类似于subset() 函数,在函数中使用它可能是一种负担(对我来说,无论如何:-D)。我可以使用subset = rlang::eval_tidy( expr( !!subpop_quo == i), data = data) 强制执行操作(使用lm() 练习)。一旦我开始进入expr() 和朋友的兔子洞,我就认为我做错了什么。 :-P 手动过滤并将其传递给模型函数对我来说似乎更简单(即dat = filter(data, !!subpop_quo == i))。
  • 谢谢,@aosmith 成功了。我总是对使用 filter() 有点犹豫,因为我不知道是否会丢失某些信息。例如,在 Stata 中,有必要使用特定的调查命令来过滤子群体以获得正确的标准误差。但是,我会对此进行试验。不幸的是,由于我不小心删除了对您的评论的支持,因此我无法投票给您。
  • 哦,对 Stata 很感兴趣。在 R 中,我总是将 subset 参数与 subset() 互换使用,但在 svyglm 中可能会有所不同!

标签: r dplyr survey quosure


【解决方案1】:

不确定是否有更好的方法,因为svyby() 似乎不支持svyglm()。这里,quo_squash() 用于将表达式传递给subset()。 这可以扩展到进行预测。

gears = unique(mtcars$gear)
lapply(gears, function(x) {
  subset(mtcars_cplx, !!quo_squash(gear == x)) %>% 
    svyglm(mpg ~ carb + cyl + carb*cyl, design = .)
})

【讨论】:

    【解决方案2】:

    我可以通过混合expr()rlang::tidy_eval() 来使用subset 参数。

    你的函数中的模型行可以读取:

    reg <- svyglm(formula, data = data, 
           subset = rlang::eval_tidy( expr( !!subpop_quo == i), data =  data) )
    

    不过,我不知道这是否可靠,或者是否有一些更直接的 tidyeval 方法。解决这个问题让我意识到subset() 函数/参数很难在函数中使用。 :-P

    【讨论】:

      猜你喜欢
      • 2021-09-02
      • 2019-07-21
      • 1970-01-01
      • 2019-02-16
      • 2017-10-18
      • 2019-07-27
      • 1970-01-01
      • 2015-01-27
      • 2022-10-17
      相关资源
      最近更新 更多