Как отфильтровать строки с несколькими условиями? - PullRequest
1 голос
/ 06 мая 2020

У меня есть набор данных, как показано ниже.

df <- tribble(
  ~shop_id,  ~id,      ~key,        ~date,      ~status, 
  "1",       "10",     "abc",    '2020-05-04',   'good',
  "1",       "10",     "def",    '2020-05-03',   'normal',
  "1",       "10",     "glm",    '2020-05-03',   'bad',
  "1",       "20",     "ksr",    '2020-05-01',   'bad',
  "1",       "20",     "tyz",    '2020-05-02',   'bad',
  "2",       "20",     "uyv",    '2020-05-01',   'good',
  "2",       "20",     "mys",    '2020-05-01',   'normal',
  "2",       "30",     "ert",    '2020-05-01',   'bad',
  "2",       "40",     "yer",    '2020-05-05',   'good',
  "2",       "40",     "tet",    '2020-05-05',   'bad',
)

Теперь я хочу отфильтровать данные со следующими условиями:

Сгруппируйте данные по shop_id и id, затем посмотрите на дату. Затем

  1. Если date минимально, когда status == 'bad', удалите строки. Например, из-за этого условия из набора данных были удалены первые три строки. (см. желаемый_df)
  2. Если есть только статус 'bad', оставьте все строки. Из-за этого условия в желаемом наборе данных остались 4-я и 5-я строки.
  3. Если date такое же среди строк, как status == 'bad', оставьте обе строки в желаемом наборе данных.

Другими словами, я хочу видеть строки только тогда, когда дата «плохого» статуса является максимальной после того, как мы сгруппировали shop_id и id. Но если дата статуса одинакова в обоих статусах, оставьте строки.


desired_df <- tribble(
  ~shop_id,  ~id,      ~key,      ~date,      ~status, 
  "1",       "20",     "ksr",   '2020-05-01',   'bad',
  "1",       "20",     "tyz",   '2020-05-02',   'bad',
  "2",       "30",     "ert",   '2020-05-01',   'bad',
  "2",       "40",     "yer",   '2020-05-05',   'good',
  "2",       "40",     "tet",   '2020-05-05',   'bad', 
)

Любая помощь будет очень признательна!

1 Ответ

2 голосов
/ 06 мая 2020

Один из подходов - использовать case_when.

df %>%
  mutate(date = ymd(date)) %>%
  group_by(shop_id,id) %>% 
  mutate(filter = case_when(all(status != "bad") ~ FALSE,
                            all(status == "bad") ~ TRUE,
                            all(status[date == min(date)] == "bad") ~ FALSE,
                            any(status[date == min(date)] == "good") ~ TRUE,
                            TRUE ~ FALSE)) %>%
  filter(filter == TRUE) %>% 
  dplyr::select(-filter)

# A tibble: 5 x 5
# Groups:   shop_id, id [3]
  shop_id id    key   date       status
  <chr>   <chr> <chr> <date>     <chr> 
1 1       20    ksr   2020-05-01 bad   
2 1       20    tyz   2020-05-02 bad   
3 2       30    ert   2020-05-01 bad   
4 2       40    yer   2020-05-05 good  
5 2       40    tet   2020-05-05 bad  
...