Search code examples
rlistdplyrmagrittr

Applying a Magrittr Pipe in lapply() with R


I would like to find a way to implement a series of piped functions through an lapply statement and generate multiple databases as a result. Here is a sample data set:

# the data
d <- tibble(
  categorical = c("a", "d", "b", "c", "a", "b", "d", "c"),
  var_1 = c(0, 0, 1, 1, 1, 0, 1, 0),
  var_2 = c(0, 1, 0, 0, 0, 0 ,1, 1),
  var_3 = c(0, 0, 1, 1, 1, 1, 1, 1),
  var_4 = c(0, 1, 0, 1, 0, 0, 0, 0)
)

Here is the outcome I want:

$var_1
a  b  c  d
1  1  1  1

$var_2
a  b  c  d
0  0  1  2

$var_3
a  b  c  d
1  2  2  1

$var_4
a  b  c  d
0  0  1  1

I can recreate each list element individually with ease. Here is my sample code with dplyr:

d %>%
  filter(var_1 == 1) %>%
  group_by(categorical, var_1) %>%
  summarise(n = n()) %>%
  select(-var_1) %>%
  rename("var_1" = "n") %>%
  ungroup() %>%
  spread(categorical, var_1)

# A tibble: 1 x 4
      a     b     c     d
  <int> <int> <int> <int>
1     1     1     1     1

But, I want to automate the process across all columns and create an object that contains each row of information as a list.

Here is where I started:

lapply(d[,2:5], function (x) d %>%
  filter(x == 1) %>%
  group_by(categorical, x) %>%
  summarise(n = n()) %>%
  select(-x) %>%
  rename("x" = "n") %>%
  ungroup() %>%
  spread(categorical, x))

Any help would be much appreciated!


Solution

  • We can gather into 'long' format, then do a group_split and spread it back after getting the sum of 'val' grouped by 'categorical'

    library(tidyverse)
    gather(d, key, val, -categorical) %>%
         split(.$key) %>%
         map(~ .x %>% 
               group_by(categorical) %>%
               summarise(val = sum(val)) %>%
               spread(categorical, val))
    #$var_1
    # A tibble: 1 x 4
    #      a     b     c     d
    #  <dbl> <dbl> <dbl> <dbl>
    #1     1     1     1     1
    
    #$var_2
    # A tibble: 1 x 4
    #      a     b     c     d
    #  <dbl> <dbl> <dbl> <dbl>
    #1     0     0     1     2
    
    #$var_3
    # A tibble: 1 x 4
    #      a     b     c     d
    #  <dbl> <dbl> <dbl> <dbl>
    #1     1     2     2     1
    
    #$var_4
    # A tibble: 1 x 4
    #      a     b     c     d
    #  <dbl> <dbl> <dbl> <dbl>
    #1     0     0     1     1
    

    Or another option is to loop through the columns except the first one, and then do the group_by sum and spread to 'wide' format

    map(names(d)[-1], ~ 
              d %>%
               group_by(categorical) %>% 
               summarise(n = sum(!! rlang::sym(.x))) %>% 
               spread(categorical, n))