Фильтровать индивидуума, который имеет два разных критерия?

#r #filter #dplyr #subset

#r #Фильтр #dplyr #подмножество

Вопрос:

TLDR: нужно фильтровать человека по двум разным критериям

В основном, учитывая приведенный ниже пример, мне нужно знать, какой человек получил и сыр, и хлеб, и возвращает строки, равные этому. В примере это аблибаба, Мэри и Стив.

Обычно несколько критериев фильтрации в dplyr довольно просты, но это просматривается в разных строках, поэтому я нахожу это довольно сложным. Я придумал длинное решение, но я уверен, что есть более эффективный способ.

Я имею дело с большим набором данных, поэтому важна скорость.

 
set.seed(1111)
df = data.frame(ID = sample(c("bob","steve","mary","alibaba"),20,replace = TRUE))
                
set.seed(1311)                
df$food = sample(c("cheese","bread","olives"),20, replace = TRUE)

# finding which individuals have both cheese and bread
index = df %>% distinct(ID,food, .keep_all = TRUE) %>% 
  filter(food == "cheese" | food == "olives") %>% 
  group_by(ID) %>% 
  summarise(freq = n()) %>% 
  filter(freq > 1) %>% {as.vector(.$ID)}

# returning the rows for the individuals that have both cheese and bread
df %>% filter(ID %in% index,food == "cheese" | food == "olives")


  

Ответ №1:

После группировки по «идентификатору» filter те группы, в которых есть как «сыр», так и «оливки», оборачиваются all и в то же время выполняют поэлементный фильтр со вторым выражением ( food %in% c('cheese', 'olives') )

 library(dplyr) 
df %>%
     group_by(ID) %>%
     filter(all(c('cheese', 'olives') %in% food), food %in% c('cheese', 'olives'))
  

-вывод

 # A tibble: 13 x 2
# Groups:   ID [3]
#   ID      food  
#   <chr>   <chr> 
# 1 alibaba olives
# 2 steve   olives
# 3 steve   olives
# 4 steve   olives
# 5 alibaba cheese
# 6 steve   olives
# 7 steve   olives
# 8 mary    cheese
# 9 alibaba olives
#10 mary    olives
#11 steve   cheese
#12 alibaba olives
#13 steve   olives
  

Или другим вариантом, который потенциально быстрее, было бы сначала filter , а затем выполнить группировку и отфильтровать те группы, которые имеют 2 разных значения в ‘food’

 df %>%
     filter(food %in% c('cheese', 'olives')) %>% 
     group_by(ID) %>%
     filter(n_distinct(food) == 2)
  

Или другой вариант с data.table

 library(data.table)
i1 <- setDT(df)[, .I[all(c('cheese', 'olives') %in% food) amp; food %in% c('cheese', 'olives')], ID]$V1
df[i1]
  

Комментарии:

1. Я думаю, что это выглядит хорошо …. не могли бы вы просто объяснить, возможно?

2. @Dasr я обновил сообщение. Надеюсь, это поможет. Если вы можете сказать мне, в чем проблема, я могу вам помочь

3. Все в порядке. Я просто пытался понять первый ответ, который вы дали. Но это работает. Спасибо.