0

I have a survey data with weight column like this dummy sample:

df <- structure(
  list(
    device = c(
      "Digital",
      "No Device",
      "No Device",
      "Digital",
      "Digital",
      "No Device",
      "Digital",
      "Digital",
      "Analouge",
      "Digital"
    ),
    sex = structure(c(1, 2, 2, 1, 1, 1, 1, 2, 2, 1), format.spss = "F8.2"),
    region = structure(c(15, 3, 18, 18, 30, 18, 54, 50, 30,
                         38), format.spss = "F8.0"),
    age_group = structure(c(3, 3,
                            5, 7, 6, 4, 7, 7, 6, 7), format.spss = "F8.2"),
    weight = structure(
      c(
        845.674012066483,
        523.065753702848,
        551.805833394951,
        454.282517089281,
        1234.09384828581,
        1046.04985735983,
        994.717870661103,
        1013.62211131793,
        1307.98181670913,
        544.360713556522
      ),
      format.spss = "F8.2"
    )
  ),
  row.names = c(NA,
                -10L),
  class = c("tbl_df", "tbl", "data.frame")
)

I am using srvyr package to make a survey object and do my analysis:

library(srvyr)
sv_sample <- df %>%
  srvyr::as_survey_design(weights = weight)

Here I am doing a cross tab interaction between device and sex for example and it is ok

sv_sample %>% 
  mutate(sex = as.factor(sex) )%>%
  mutate_at(vars(device),
            fct_explicit_na,
            na_level = "to_impute") %>%
  group_by(sex ,device) %>%
  summarize(
    proportion = srvyr::survey_mean(na.rm = TRUE),
    total = srvyr::survey_total(na.rm = TRUE)
  ) %>%
  select(-proportion_se, -total_se) %>%
  ungroup()

output:

# A tibble: 5 x 4
  sex   device    proportion total
  <fct> <fct>          <dbl> <dbl>
1 1     Digital        0.796 4073.
2 1     No Device      0.204 1046.
3 2     Analouge       0.385 1308.
4 2     Digital        0.298 1014.
5 2     No Device      0.316 1075.

I need to create similar cross tab for device vs other demo variables in my data like age , region , family_size etc etc so instead of copy & paste the cross tab snippet several times I tried to make a function with Curly curly operator. What am I missing here?

    crosstab <- function(survey_data, vars1 , vars2) {
      mutate(demo = as.factor{{ vars1 }} )%>%
        mutate_at(vars{{ vars2 }},
                  fct_explicit_na,
                  na_level = "to_impute") %>%
        group_by(demo ,{{ vars2 }}) %>%
        summarize(
          proportion = srvyr::survey_mean(na.rm = TRUE),
          total = srvyr::survey_total(na.rm = TRUE) ) %>%
        select(-proportion_se, -total_se) %>%
        ungroup()
}

 crosstab(sv_sample, sex ,device)
DanG
  • 689
  • 1
  • 16
  • 39

1 Answers1

1

Two things:

  1. vars{{ vars2 }} is invalid syntax. vars is a function: vars({{vars2}}). Same for as.factor.

  2. {{…}} interpolates a single value. If you want to pass multiple values, you either need to use !!! in combination with enquos or you can just pass the variables in dots (i.e. ...), no need for metaprogramming.

    However, in your case it seems as if you’re actually only passing a single variable name, so instead it would probably appropriate to rename vars1 and vars2 to var1 and var1 — or, better yet, give them proper names: var1 is an un-descriptive, cryptic variable name.

Instead of mutate_at(vars(...), f), also consider using its modern replacement, mutate(across(..., f)); this further simplifies your code. See Taking multiple columns without ....

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • I didnot fully get your second point . did you mean rename or still I need to use `{{…}}` `function(survey_data, demo1 , demo2) { mutate(demo = as.factor vars({{demo1}}) )%>% mutate_at(vars({{demo2}}), fct_explicit_na, na_level = "to_impute") %>% group_by(demo1 ,{{demo2}}) %>% summarize( proportion = srvyr::survey_mean(na.rm = TRUE), total = srvyr::survey_total(na.rm = TRUE) ) %>% select(-proportion_se, -total_se) %>% ungroup()` – DanG Dec 01 '21 at 10:04
  • 1
    @DanG Well, using `demo1` instead of `vars1` hasn’t improved the variable name. Either way, the second point only applies if you try to pass multiple names to `vars1` or `vars2`, in which case your code won’t work. If you pass single names only, that code is fine (but you should still find more descriptive variable names). – Konrad Rudolph Dec 01 '21 at 10:16
  • 2
    Hi Konrad. `enexprs()` is a function for experts only. We've updated the rlang doc to make this clearer. Could you please mention `enquos()` in this post? Thanks :) Even better, the standard way of going from one `{{` var to multiple is to pass a selection to `across()`, this way no metaprogramming is needed. – Lionel Henry Dec 01 '21 at 11:09
  • @LionelHenry Great work on the new ‘rlang’ documentation, looking very nice! – Konrad Rudolph Dec 01 '21 at 11:21