Ищем функцию dplyr для условного применения фильтра - PullRequest
5 голосов
/ 26 марта 2020

У меня есть фрейм данных с различными значениями гематологии и временем их сбора. Эти значения должны собираться только в определенные c раз, но иногда добавляется дополнительное. Я хочу удалить все случаи, когда значение было собрано вне запланированного времени.

Чтобы проиллюстрировать эту проблему, вот некоторый код для создания очень упрощенной версии фрейма данных, с которым я работаю (плюс некоторые примеры расписаний). ):

example <- tibble("Parameter" = c(rep("hgb", 3), rep("bili", 3), rep("LDH", 3)), 
                  "Collection" = c(1, 3, 4, 1, 5, 6, 0, 4, 8))

hgb_sampling <- c(1, 4)
bili_sampling <- c(1, 5)
ldh_sampling <- c(0, 4)

Итак, мне нужен способ условно применить фильтр на основе значения в столбце Параметр. Решение должно вписаться в конвейер dyplr и дать что-то вроде этого:

filtered <- tibble("Parameter" = c(rep("hemoglobin", 2), rep("bilirubin", 2), rep("LDH", 2)), 
                  "Collection" = c(1, 4, 1, 5, 0, 4))

Я пробовал пару вещей (все они равносильны приведенному ниже), но использование «Параметра» отключает вещи up:

df <- example %>%
  {if (Parameter == "hgb") filter(., Collection %in% hgb_sampling)} 

Есть предложения?

Ответы [ 6 ]

3 голосов
/ 26 марта 2020

Вы можете создать ссылочный тиббл, присоединить его к example и оставить только выбранные строки.

library(dplyr)

ref_df <- tibble::tibble(Parameter = c("hgb","bili", "LDH"), 
                         value  = list(c(1, 4), c(1, 5), c(0, 4)))

example %>%
  inner_join(ref_df, by = 'Parameter') %>%
  group_by(Parameter) %>%
  filter(Collection %in% unique(unlist(value))) %>%
  select(Parameter, Collection)

#  Parameter Collection
#  <chr>          <dbl>
#1 hgb                1
#2 hgb                4
#3 bili               1
#4 bili               5
#5 LDH                0
#6 LDH                4
2 голосов
/ 26 марта 2020

Попробуйте purrr::imap_dfr:

library(tidyverse)

example <- tibble("Parameter" = c(rep("hgb", 3), rep("bili", 3), rep("LDH", 3)), 
                  "Collection" = c(1, 3, 4, 1, 5, 6, 0, 4, 8))

l <- list(hgb = c(1, 4), bili = c(1, 5), LDH = c(0, 4))

imap_dfr(l, ~example %>%
           filter(Parameter == .y & Collection %in% .x))

# # A tibble: 6 x 2
# Parameter Collection
# <chr>          <dbl>
#   1 hgb                1
# 2 hgb                4
# 3 bili               1
# 4 bili               5
# 5 LDH                0
# 6 LDH                4
2 голосов
/ 26 марта 2020

Положите ваши действительные времена в список с именами, совпадающими с именами в Collection, затем сгруппируйте по значениям в Collection и отфильтруйте по значениям каждого элемента списка в sample_list:

sample_list <- list(hgb = c(1, 4), bili = c(1, 5), LDH = c(0, 4))

example %>% 
    group_by(Parameter) %>% 
    filter(Collection %in% sample_list[[first(Parameter)]])

Вывод:

# A tibble: 6 x 2
  Parameter  Collection
  <chr>           <dbl>
1 hemoglobin          1
2 hemoglobin          4
3 bilirubin           1
4 bilirubin           5
5 LDH                 0
6 LDH                 4
1 голос
/ 26 марта 2020

Простой метод, который очень легко изменить, добавить, удалить, отладить, ...

library(dplyr)

example %>%
  filter(Parameter=="hgb" & Collection %in% c(1, 4) |
         Parameter=="bili" & Collection %in% c(1, 5) |
         Parameter=="LDH" & Collection %in% c(0, 4) )

Или, если вы хотите, чтобы значения были в диапазоне:

example %>%
  filter(Parameter=="hgb" & between(Collection, 1, 4) |
         Parameter=="bili" & between(Collection, 1, 5) |
         Parameter=="LDH" & between(Collection, 0, 4))
1 голос
/ 26 марта 2020

дополнительный раствор

library(tidyverse)
library(purrr)
fltr <- list(hgb = c(1, 4), bili = c(1, 5), LDH = c(0,4)) %>% 
  enframe(name = "Parameter")

example %>% 
  group_by(Parameter) %>% 
  nest() %>% 
  left_join(fltr) %>% 
  mutate(out = map2(.x = data, .y = value, .f = ~ filter(.x, Collection %in% .y))) %>% 
  unnest(out) %>% 
  select(Parameter, Collection)
1 голос
/ 26 марта 2020

Один параметр, включающий dplyr, stringr и tibble, может быть:

enframe(mget(ls(pattern = "sampling"))) %>%
 mutate(name = str_extract(name, "[^_]+")) %>%
 right_join(example %>%
             mutate(Parameter = tolower(Parameter)), by = c("name" = "Parameter")) %>%
 filter(Collection %in% unlist(value)) %>%
 select(-value)

  name  Collection
  <chr>      <dbl>
1 hgb            1
2 hgb            4
3 bili           1
4 bili           5
5 ldh            0
6 ldh            4

Если он хранится в отдельном df, как показано @Ronak Shah, вы можете сделать:

example %>%
 filter(Collection %in% unlist(ref_df$value[match(Parameter, ref_df$Parameter)]))
...