фильтровать фрейм данных по нескольким столбцам с помощью base или dplyr - PullRequest
0 голосов
/ 12 июля 2020

Я пытаюсь фильтровать строки кадра данных на основе столбцов в другой дейтаграмме. По сути, я хочу извлекать строки с одинаковыми идентификаторами, где позиция находится между началом и концом. Есть дополнительная уловка, заключающаяся в том, что идентификаторы форматируются по-другому. наконец, объем данных, задействованных в скрипте, очень велик, поэтому для экономии памяти или скорости полезно иметь. был бы благодарен за несколько советов.

library(dplyr)

df1 <- data.frame(id = c(1, 1, 1, 2, 2, 2, 3, 3, 3), 
                  pos = c(30, 40, 50, 35, 45, 55, 60, 63, 39))

df2 <- data.frame(idstr = c("id1", "id1", "id3", "id4", "id4"), 
                  start=c(30, 20, 30, 40, 20 ),
                  end = c(40, 30, 50, 60, 45))

df.base <- df1[ paste0("id", df1$id) == df2$idstr && 
                 df1$pos >= df2$start &&
                 df1$pos <= df2$end,]

df.dplyr <- df1 %>%
            left_join(df2, by  = c('id' == 'idstr') ) %>%
            filter(pos >= start & pos <= end) %>%
            select(id, pos)

edit: ожидаемый результат, строки из df1 соответствуют условию (их позиция находится в диапазоне df2 с тем же идентификатором), поэтому, если нет ошибки: id , поз 1, 30 1, 40 3, 39

объяснение: например, df1 [3,] id == 1 и pos == 50 глядя на df2, нет строки, где df2 $ id == "id1" и df2 $ start < = 50 и df2 $ end> ​​= 50, поэтому df1 [3,] будет отфильтрован.

Ответы [ 2 ]

2 голосов
/ 12 июля 2020

Мы можем использовать неэквивалентное соединение в data.table. Создайте 'id', похожий на оба набора данных, а затем объедините on столбцы 'id' и неэквивалентное соединение с 'pos' и 'start', 'end' столбцами

library(data.table)
setDT(df1)[, id := paste0('id', id)]
df1[df2, on = .(id = idstr, pos >= start, pos <= end)]
1 голос
/ 12 июля 2020

Я взял ваши 2 DF df1 и df2, измененный столбец idstr из df2 в число c путем извлечения цифр. Затем с помощью left_join, group_by и filter я получаю результат.

library(dplyr)


df1 <- data.frame(id = c(1, 1, 1, 2, 2, 2, 3, 3, 3), pos = c(30, 40, 50, 35, 45, 55, 60, 63, 39))

df2 <- data.frame(idstr = c("id1", "id1", "id3", "id4", "id4"), 
                  start=c(30, 20, 30, 40, 20 ),
                  end = c(40, 30, 50, 60, 45))


df2 %>% 
  mutate(idstr = as.numeric(stringr::str_extract(idstr, '[0-9]'))) %>% 
  left_join(df1, by = c('idstr' = 'id')) %>% 
  dplyr::filter(pos >= start & pos <= end)
#> # A tibble: 4 x 4
#> # Groups:   idstr [2]
#>   idstr start   end   pos
#>   <dbl> <dbl> <dbl> <dbl>
#> 1     1    30    40    30
#> 2     1    30    40    40
#> 3     1    20    30    30
#> 4     3    30    50    39

Есть один df1$id == 1, который помещается в 2 слота начала-конца в df2. И поэтому должно быть 3 позиции с id = 1. Если одно из ограничений является исключительным, как в следующем коде, оно подходит для вашего Wi-Fi sh.


df2 %>% 
  mutate(idstr = as.numeric(stringr::str_extract(idstr, '[0-9]'))) %>% 
  left_join(df1, by = c('idstr' = 'id')) %>% 
  dplyr::filter(pos > start & pos <= end)

#>   idstr start end pos
#> 1     1    30  40  40
#> 2     1    20  30  30
#> 3     3    30  50  39
...