R: better way to filter by group and vector of values?

Viewed 240

I have a dataframe containing values and type. I want to filter the df to:

  • contain only types that contains all of the values in vector
  • keep only specific values by type.

I can accomplish this in two step filtering, but it seems quite error prone. Maybe because the order of filter(keep.val %in% vals) and filter(vals %in% keep.val) is just in reverse, but create different output?

Here is my dummy data:

   keep.val = c(1,3)
   d <- data.frame(type = rep(c("a", "b", "d"), each = 4),
                vals = as.integer(c(1:4, 3:6, 1,3,4,5)))

My double filtering:

d %>% 
  group_by(type) %>% 
  filter(all(keep.val %in% vals)) %>%   # need to get two filters: one to keep only group that have all values
  filter(vals %in% keep.val)            # second to keep only specific values

My desired output (now it is correct with double filtering):

  type   vals
  <fct> <int>
1 a         1
2 a         3
3 d         1
4 d         3

I was wondering if there is a way to make filter just once, and clarify where I am filtering for what? Mostly for future me looking back in code :)

3 Answers

You can do it in one call of filter with &. Not that it's that much better.

d %>% 
   group_by(type) %>% 
   filter(all(keep.val %in% vals) & (vals %in% keep.val))

You could combine the two filter :

library(dplyr)

d %>%
  group_by(type) %>% 
  filter(all(keep.val %in% vals) & vals %in% keep.val)
  #filter(all(keep.val %in% vals), vals %in% keep.val)


#  type   vals
#  <fct> <int>
#1 a         1
#2 a         3
#3 d         1
#4 d         3

With data.table

library(data.table)
setDT(d)[,.SD[all(keep.val %in% vals) & (vals %in% keep.val)] , type]

Or using slice in dplyr

library(dplyr)
d %>%
   group_by(type) %>%
   slice(which(all(keep.val %in% vals) & vals %in% keep.val))
Related