фильтровать один кадр данных через условия в другом - PullRequest
1 голос
/ 06 апреля 2020

Я хочу рекурсивно фильтровать фрейм данных, d по произвольному числу условий (представленных в виде строк в другом фрейме данных z).

Я начинаю с фрейма данных d:

d <- data.frame(x = 1:10, y = letters[1:10])

Второй кадр данных z содержит столбцы x1 и x2, которые являются нижним и верхним пределами фильтрации d$x. Этот фрейм данных z может вырасти до произвольного числа строк.

z <- data.frame(x1 = c(1,3,8), x2 = c(1,4,10))

Я хочу вернуть все строки d, для которых d$x <= z$x1[i] и d$x >= z$x2[i] для всех i, где i = nrow(z).

Так что для этого игрушечного примера исключите все из 1: 1, 3: 4, 8:10 включительно.

   x  y
2  2  b 
5  5  e
6  6  f
7  7  g

Ответы [ 2 ]

1 голос
/ 06 апреля 2020

Мы можем создать последовательность между значениями x1 и x2 и использовать anti_join для выбора строк из d, которых нет в z.

library(tidyverse)

remove <- z %>%
  mutate(x = map2(x1, x2, seq)) %>%
  unnest(x) %>%
  select(x)

anti_join(d, remove)

#  x y
#1 2 b
#2 5 e
#3 6 f
#4 7 g
1 голос
/ 06 апреля 2020

Мы можем использовать неэквивалентное объединение

library(data.table)
i1 <- setDT(d)[z, .I, on = .(x >=x1, x <= x2), by = .EACHI]$I
i1
#[1]  1  3  4  8  9 10
d[i1]
#    x y
#1:  1 a
#2:  3 c
#3:  4 d
#4:  8 h
#5:  9 i
#6: 10 j
d[!i1]
#   x y
#1: 2 b
#2: 5 e
#3: 6 f
#4: 7 g

Или использовать fuzzyjoin

library(fuzzyjoin)
library(dplyr)
fuzzy_inner_join(d, z, by = c('x' = 'x1', 'x' = 'x2'),
        match_fun = list(`>=`, `<=`)) %>% 
     select(names(d))
# A tibble: 6 x 2
#      x y    
#  <int> <fct>
#1     1 a    
#2     3 c    
#3     4 d    
#4     8 h    
#5     9 i    
#6    10 j    

Или получить строки не в 'x' из 'd '

fuzzy_anti_join(d, z, by = c('x' = 'x1', 'x' = 'x2'),
        match_fun = list(`>=`, `<=`)) %>% 
     select(names(d))
# A tibble: 4 x 2
#      x y    
#  <int> <fct>
#1     2 b    
#2     5 e    
#3     6 f    
#4     7 g    
...