Mike
Mike

Reputation: 2107

Using purrr to iterate over two lists and then pipe into dplyr::filter across a list of data frames

library(tidyverse)
library(purrr)

This is a continuation of the question: "Using Purrr to Iterate Over Two Lists and Then Pipe into Dplyr::Filter".

Using the sample data below, I first create a data frame (wanted) containing values that I want to feed to dplyr::filter. I then use the code below to create a data frame of the results.

map2_dfr(wanted$School, wanted$Code, ~filter(DF, School == .x, Code == .y)) %>% 
group_by(School, Code) %>% 
summarise_all(sum)

However, my actual data is across three different datasets, from three different time periods. For this example, I just made two additional copies of DF, and then put them into a list

DF2 <- DF
DF3 <- DF

DFList <- list(DF, DF2, DF3)

Now, in order to work across each data frame in the list, I have to use purrr:::map and something like the code below...

DFList %>%
   map(~filter(.x, School == "School1", Code == "B344")) %>%
   map(~group_by(.x, School, Code)) %>%
   map(~summarise(.x, Count = sum(Question1)))

This is where I'm stuck. I want to combine the two approaches above in order to iterate over wanted, feed these values into dplyr::filter, but now I have to do this across a list of data frames and output a list of three data frames.

I'm struggling with something like the code below...which doesn't work. Any suggestions? Using so many maps doesn't seem the best way as well...

map2_dfr(Wanted$School, Wanted$Code, 
    ~DFList %>% 
        map(~filter(.x, School == .x, Code == .y) %>% 
        map(~group_by(.x, Code, School) %>% 
        map(~summarise(.x, Count = sum(Question1))))))

Sample Data:

Code <- c("B344","B555","S300","T220","B888","B888","B555","B344","B344","T220","B555","B555","S300","B555","S300","S300","S300","S300","B344","B344","B888","B888","B888")
School <- c("School1","School1","School2","School3","School4","School4","School1","School1","School3","School3","School4","School1","School1","School3","School2","School2","    School4","School2","School3","School4","School3","School1","School2")
Question1 <- c(3,4,5,4,5,5,5,4,5,3,4,5,4,5,4,3,3,3,4,5,4,3,3)
Question2 <- c(5,4,3,4,3,5,4,3,2,3,4,5,4,5,4,3,4,4,5,4,3,3,4)
DF <- data_frame(Code, School, Question1, Question2)

wanted <- data_frame(School = c("School2", "School1"),
                     Code = c("S300", "B344"))

Upvotes: 1

Views: 316

Answers (1)

alistaire
alistaire

Reputation: 43364

Since the data frame in the list are in the same format, just coerce them into a single data frame with dplyr::bind_rows, saving the element name by passing an .id parameter, which can be used for grouping after filtering by joining with wanted:

library(tidyverse)

DF <- data_frame(Code = c("B344", "B555", "S300", "T220", "B888", "B888", "B555", "B344", "B344", "T220", "B555", "B555", "S300", "B555", "S300", "S300", "S300", "S300", "B344", "B344", "B888", "B888", "B888"), 
                 School = c("School1", "School1", "School2", "School3", "School4", "School4", "School1", "School1", "School3", "School3", "School4", "School1", "School1", "School3", "School2", "School2", "School4", "School2", "School3", "School4", "School3", "School1", "School2"), 
                 Question1 = c(3, 4, 5, 4, 5, 5, 5, 4, 5, 3, 4, 5, 4, 5, 4, 3, 3, 3, 4, 5, 4, 3, 3), 
                 Question2 = c(5, 4, 3, 4, 3, 5, 4, 3, 2, 3, 4, 5, 4, 5, 4, 3, 4, 4, 5, 4, 3, 3, 4))

wanted <- data_frame(School = c("School2", "School1"),
                     Code = c("S300", "B344"))

DFList <- list(DF, DF, DF)

DFList %>% 
    bind_rows(.id = 'id') %>% 
    inner_join(wanted) %>% 
    group_by(id, School, Code) %>% 
    summarise_all(sum)
#> Joining, by = c("Code", "School")
#> # A tibble: 6 x 5
#> # Groups: id, School [?]
#>   id    School  Code  Question1 Question2
#>   <chr> <chr>   <chr>     <dbl>     <dbl>
#> 1 1     School1 B344       7.00      8.00
#> 2 1     School2 S300      15.0      14.0 
#> 3 2     School1 B344       7.00      8.00
#> 4 2     School2 S300      15.0      14.0 
#> 5 3     School1 B344       7.00      8.00
#> 6 3     School2 S300      15.0      14.0

Upvotes: 2

Related Questions