Using string vectors as variables in a function using dplyr::summarise()

Viewed 199

I recently started using R to work on my research data (and have definitely not regretted leaving SPSS) and can't find a way to solve the following problem: I have created a function which groups my data by a binary variable (did the patient suffer a certain type of complication yes/no? -> reg_var) and runs the summarise function of dplyr on a continuous variable which is associated to the binary variable (how high was the estimated risk for mentioned complication -> reg_yr). I now want to run this function for multiple pairs of variables (e.g. compare(reg_var1, reg_yr1), compare(reg_var2, reg_yr2) and compare(reg_var3, reg_yr3)) and create multiple tibbles which I can merge later. I have created two vectors containing the names of the variables (v_reg_var and v_reg_yr).

    library(tidyverse)
    # Create a function to calculate and compare est. risk percentages
    # of patients with/without actual complications
    compare <-function(reg_var, reg_yr) {
    datatable %>%
    group_by(.data[[reg_var]]) %>%
    summarise(
    n(), mean(.data[[reg_yr]]), sd(.data[[reg_yr]]), median(.data[[reg_yr]]), min(.data[[reg_yr]]), max(.data[[reg_yr]]),
    "25%" = quantile(.data[[reg_yr]], probs = 0.25),
    "50%" = quantile(.data[[reg_yr]], probs = 0.5),
    "75%" = quantile(.data[[reg_yr]], probs = 0.75))
    }
    v_reg_var <- c[reg_var1, reg_var2, reg_var3, …)
    v_reg_yr <- c[reg_yr1, reg_yr2, reg_yr3, …)
    # Now if I run compare() using two vectors which only contain one character string it works just
    # fine but unfortunately if I run compare(v_reg_var, v_reg_yr), I receive the following error:

    compare(v_reg_var, v_reg_yr)

   Error: Problem with \mutate()` input `..1`.`
   x Must subset the data pronoun with a string
   ℹ Input \..1` is `<unknown>`.`

It’d be great if anyone could give me a hint at what I’m doing wrong here or if there’s a more elegant solution.

2 Answers

compare function takes one value of v_reg_var and v_reg_yr at a time. To pass them one by one in parallel you can use Map.

Map(compare, v_reg_var, v_reg_yr)

Or since you are using mostly tidyverse, equivalent is map2 from purrr.

purrr::map2(v_reg_var, v_reg_yr, compare)

map2 would return list of dataframes. If you want to get all the data in one dataframe you can use purrr::map2_df.

The function you have works only for 1 variable and does not iterate through all the variables. First we simplify the function by calling the base R summary function, and using !!as.name() instead of calling it from the data.frame (which is perfectly correct) :

fn = function(V){
   c(n=length(V),sd=sd(V),summary(V))
}

library(tidyverse)

datatable = data.frame(y1=sample(1:5,100,replace=TRUE),
y2=sample(1:5,100,replace=TRUE),
v1=runif(100),v2=runif(100))
    
compare <-function(df,reg_var,reg_yr) {
    df %>%
    group_by(!!as.name(reg_yr)) %>%
    summarise(res=list(fn( !!as.name(reg_var) ) ) )%>% 
    unnest_wider(res)
    }

compare(datatable,"v1","y1")
# A tibble: 5 x 9
     y1     n    sd   Min. `1st Qu.` Median  Mean `3rd Qu.`  Max.
  <int> <dbl> <dbl>  <dbl>     <dbl>  <dbl> <dbl>     <dbl> <dbl>
1     1    18 0.267 0.0241    0.185   0.276 0.373     0.568 0.814
2     2    24 0.288 0.0443    0.243   0.396 0.470     0.664 0.986
3     3    20 0.330 0.0446    0.234   0.474 0.501     0.777 0.987
4     4    14 0.203 0.0171    0.0566  0.208 0.247     0.408 0.600
5     5    24 0.299 0.0138    0.235   0.457 0.491     0.742 0.948

Now we iterate through your pairs:

v_reg_var <- c("v1","v2")
v_reg_yr <- c("y1","y2")

1:length(v_reg_var) %>% 
map(~compare(datatable,v_reg_var[.x],v_reg_yr[.x]))

This last part similar to @RonakShah's solution, just that it's my preference to avoid calling from the global environment.

Also I suspect your original table could be made into a long format and this would be easier

Related