Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Summarising multiple variables without iteration

Tags:

r

tidyverse

Consider this data that needs the summary measures mean and sd on multiple variables,

# Create grouping var; ####
mtcars <- mtcars %>% mutate(
        am = case_when(
                am == 0 ~ "Automatic",
                TRUE ~ "Manual"
        )
)

With the following custom function and purrr, I can create a baseline table,

# Summarising function; ####
sum_foo <- function(data, var) {
        
        data %>% 
                group_by(am) %>% 
                summarise(
                        mean = mean( !!sym(var) , na.rm = TRUE),
                        sd   = sd( !!sym(var) , na.rm = TRUE)
                ) %>% 
                mutate(across(where(is.double), round, 2)) %>%  
                group_by(am) %>% 
                transmute(
                        value = paste(mean, "(±", sd, ")", sep = ""),
                        variable = var
                ) %>%
                pivot_wider(
                        names_from = "am"
                )
        
        
}


# Execute Function; ####
sum_variables <- c("mpg", "hp", "disp")


sum_variables %>% map(
        sum_foo,
        data = mtcars
) %>% reduce(
        bind_rows
)

Which gives the following output,

# A tibble: 3 x 3
  variable Automatic       Manual        
  <chr>    <chr>           <chr>         
1 mpg      17.15(±3.83)    24.39(±6.17)  
2 hp       160.26(±53.91)  126.85(±84.06)
3 disp     290.38(±110.17) 143.53(±87.2) 

I want to get the output without using map and reduce, ie. without iterating through the variables with rowwise or map.

I'm looking for an alternative tidyverse-solution!

like image 998
Serkan Avatar asked Jul 25 '21 17:07

Serkan


2 Answers

Maybe you could use this solution:

library(dplyr)
library(tidyr)
library(tibble)

sum_variables %>%
  enframe() %>%
  rowwise() %>%
  mutate(output = list(sum_foo(mtcars, value))) %>%
  select(output) %>%
  unnest(cols = output)

# A tibble: 3 x 3
  variable Automatic       Manual        
  <chr>    <chr>           <chr>         
1 mpg      17.15(±3.83)    24.39(±6.17)  
2 hp       160.26(±53.91)  126.85(±84.06)
3 disp     290.38(±110.17) 143.53(±87.2) 

Updated Or you could even modify your function in the following way:

sum_foo2 <- function(data, var) {
  data %>% 
    group_by(am) %>% 
    summarise(across(all_of(var), list(Mean = mean, sd = sd))) %>% 
    mutate(across(where(is.double), round, 2)) %>%  
    group_by(am) %>%
    summarise(across(ends_with("Mean"), ~ paste(.x, "(±", get(gsub("_Mean", "_sd", cur_column())), ")", sep = ""))) %>%
    pivot_longer(!am, names_to = "Mean", values_to = "Val") %>%
    pivot_wider(names_from = "am", values_from = "Val")
}

sum_foo2(mtcars, sum_variables)

# A tibble: 3 x 3
  Mean      Automatic       Manual        
  <chr>     <chr>           <chr>         
1 mpg_Mean  17.15(±3.83)    24.39(±6.17)  
2 hp_Mean   160.26(±53.91)  126.85(±84.06)
3 disp_Mean 290.38(±110.17) 143.53(±87.2) 
 

If I am to trim the function above into a more concise version:

sum_foo2 <- function(data, var) {
  data %>%
    group_by(am) %>%
    summarise(across(all_of(var), ~ paste0(round(mean(.x), 2), "(±", round(sd(.x), 2), ")"))) %>%
    pivot_longer(!am, names_to = "Mean", values_to = "Val") %>%
    pivot_wider(names_from = "am", values_from = "Val")
}

sum_foo2(mtcars, sum_variables)
like image 114
Anoushiravan R Avatar answered Nov 29 '22 21:11

Anoushiravan R


Without using the function that you wrote, which require an iteration, ie rowwise/map, You could simply do:

sum_variables <- c("mpg", "hp", "disp")
mtcars %>%
  group_by(am) %>%
  summarise(across(all_of(sum_variables),
        ~sprintf('%.2f(\u00B1%.2f)', mean(.x), sd(.x))), .groups = 'drop') %>%
  data.table::transpose(keep.names = 'variable', make.names = TRUE)

 variable       Automatic         Manual
1      mpg    17.15(±3.83)   24.39(±6.17)
2       hp  160.26(±53.91) 126.85(±84.06)
3     disp 290.38(±110.17) 143.53(±87.20)
like image 26
KU99 Avatar answered Nov 29 '22 19:11

KU99