Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

filter list variable in dplyr

Tags:

r

dplyr

In general how do we filter by a list variable in dplyr?

E.g. a data frame where one variable is a list of different classes of object:

aa <- tibble(ss = c(1,2),
             dd = list(NA,
                       matrix(data = c(1,2,3,4),
                              nrow = 2,
                              ncol = 2)))

> aa
# A tibble: 2 x 2
#     ss dd           
#  <dbl> <list>       
#1  1.00 <lgl [1]>    
#2  2.00 <dbl [2 × 2]>

For example if I want to filter for logicals (though could be anything), if it were not a list it would be as simple as:

aa %>% filter(is.logical(dd))

But this returns

# A tibble: 0 x 2
# ... with 2 variables: ss <dbl>, dd <list>

Because it's not the first element that's a logical, it's the first element of the first element:

> is.logical(aa$dd[1])
# [1] FALSE
> is.logical(aa$dd[[1]])
# [1] TRUE

One may use purrr:map for other operations on nested list variables, but this also doesn't work.

> aa %>% filter(map(.x = dd,
+                   .f = is.logical))
# Error in filter_impl(.data, quo) : basic_string::resize

What am I missing here?

like image 580
Scransom Avatar asked Aug 02 '26 23:08

Scransom


2 Answers

As the 'dd' is a list column, we can loop through the 'dd' using map, but each element of 'dd' can have more than one element, so we make a condition that if all the elements are NA, then filter the rows of the dataset

library(tidyverse)
aa %>%
   filter(map_lgl(dd, ~ .x %>%
                           is.na %>% 
                             all))
# A tibble: 1 x 2
#     ss dd       
#   <dbl> <list>   
#1     1 <lgl [1]>

If this is about filtering based on class.

aa %>%
    filter(map_lgl(dd, is.logical))
# A tibble: 1 x 2
#     ss dd       
#  <dbl> <list>   
#1     1 <lgl [1]>

In the OP's code, map output is still a list, we convert it to a logical vector with map_lgl

like image 167
akrun Avatar answered Aug 04 '26 15:08

akrun


The best I can do is to create a dummy variable using is.logical with purrr:map, unlist it, filter by it, then un-select the dummy variable. Works, but what a kerfuffle.

aa %>%
  mutate(ff = map(.x = dd,
                       .f = is.logical),
         ff = unlist(ff)) %>%
  filter(ff == TRUE) %>%
  select(-ff)

# A tibble: 1 x 2
#      ss dd       
#   <dbl> <list>   
# 1  1.00 <lgl [1]>
like image 42
Scransom Avatar answered Aug 04 '26 15:08

Scransom