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?
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
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]>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With