Search code examples
rfunctional-programmingtidyversesurveytidyeval

How to use tidy evaluation with a non-tidyverse package


I am trying to develop a function which will calculate the means, standard error, and confidence intervals of some survey data. I need to do this repeatedly over a number of different variables with a bunch of different filter statements.

DATA

df  <-  data.frame(address_id = rep(c(1,1,1,2,2,2,3,3,3,4,4,4),5),
                   person_id = rep(c(1,2,3),20),
                   sex = as.factor(rep(c("male","female"),30)),
                   response_var = as.factor(rep(seq(1,6,1))),
                   weight = runif(60, 50, 200))

Example that works without function

# create survey design
design <- survey::svydesign(data = df, 
                              strata = ~ address_id, 
                              id = ~ person_id,
                              nest = TRUE, 
                              weights = ~ weight)

# calcualte weighted mean 
mean_se <- survey::svymean(~sex, design)

# calculate confidence intervals 
ci <- survey::confint(df_mean)

My function

create_mean_and_cis <- function(data, var){

design <- survey::svydesign(data = data, 
                            strata = ~ address_id, 
                            id = ~ person_id,
                            nest = TRUE, 
                            weights = ~ weight)

 mean_se <- survey::svymean(~{{var}}, design)
 
 ci <- confint(mean_se)%>%
   tibble::as_tibble()%>%
   tibble::rownames_to_column("variable")
 
 output <- mean_se%>%
   tibble::as_tibble()%>%
   tibble::rownames_to_column("variable")%>%
   dplyr::left_join(ci)

return(output)
}

# function call
create_mean_and_cis(sex)

When I run, I get an error message saying:

Error in survey::svydesign(data = data, strata = ~address_id, id = ~person_id,  : 
  object 'sex' not found

I can't understand what is going wrong. The tidy evaluation works perfectly when I use the curly-curly "{{var}}" within other functions. Why doesn't it work here? Can anyone help?

I have tried several variations of quasiquotation including: !!enquo(sex), sym(sex), !!sym(sex), {{sex}}, eval(parse(sex)). None of which have yielded working results.


Solution

  • If you wanted to use more advanced tidy evaulation features, you can use rlang::eval_tidy

    mean_se <- rlang::eval_tidy(rlang::quo(survey::svymean(~{{var}}, design)))
    

    You wrap your expression in a quosure where you can use the {{ }} and !! style syntax. Both quo and eval_tidy will recognize this syntax. These features are unique to functions that use the rlang package; you cannot use them directly any arbitrary R function without some sort of rlang wrapper.

    Or per @Lionel's suggestion, you can use rlang::inject to build the formula and pass that to svymean

    formula <- rlang::inject(~!!substitute(var))
    mean_se <- survey::svymean(formula, design)