在另一个表的同一行的多个列上过滤df?

时间:2019-07-25 19:02:58

标签: r dplyr

我有一个数据集,其中包含事件的开始和结束时间(称为df_time),另一个数据集具有事件发生的时间(df_val)。我想使用df_time仅将df_val过滤为记录的时间间隔内发生的事件。

尽管如此,我还是迷失了。

start = c(1, 5, 7, 4)
end = c(2, 7, 11, 7)
df_time = data.frame(start, end)

time = c(3, 6, 2, 10, 11)
val = c(100, 20, 30, 40, 50)
df_val = data.frame(time, val)

df_val %>% select_all() %>%
  filter(time >= df_time$start & time <= df_time$end)

输出:

  time val
1    6  20
Warning messages:
1: In time >= df_time$start :
  longer object length is not a multiple of shorter object length
2: In time <= df_time$end :
  longer object length is not a multiple of shorter object length

上面的命令将带有警告消息(如上),并给我错误的输出(忽略等于值时间戳的开始/结束)。在上面,应该打印除3以外的所有值。

我不确定如何解决此问题,将不胜感激!

2 个答案:

答案 0 :(得分:1)

这是您要实现的目标吗?

library(tidyverse)
start = c(1, 5, 7, 4)
end = c(2, 7, 11, 7)
df_time = data.frame(start, end)

time = c(3, 6, 2, 10, 11)
val = c(100, 20, 30, 40, 50)
df_val = data.frame(time, val)

# return one row for each start/end pair that time falls between
map2_dfr(start, end, ~filter(df_val, time >= .x, time <= .y) %>% mutate(start = .x, end = .y))
#>   time val start end
#> 1    2  30     1   2
#> 2    6  20     5   7
#> 3   10  40     7  11
#> 4   11  50     7  11
#> 5    6  20     4   7

#return unique pairs
map2_dfr(start, end, ~filter(df_val, time >= .x, time <= .y)) %>% unique()
#>   time val
#> 1    2  30
#> 2    6  20
#> 3   10  40
#> 4   11  50

#simpler method, probably
df_val %>% filter(map_lgl(time, ~any((.x >= start) & .x <= end)))
#>   time val
#> 1    6  20
#> 2    2  30
#> 3   10  40
#> 4   11  50

reprex package(v0.2.1)于2019-07-25创建

编辑:添加了一些替代方法

答案 1 :(得分:0)

这是使用data.table使用非等价内部联接的另一种选择:

library(data.table)
setDT(df_time)
setDT(df_val)

df_time[df_val, on=.(ID, start<time, end>time), nomatch=0L, 
    c(mget(paste0("x.", names(df_time))), mget(paste0("i.", names(df_val))))]

输出:

   x.ID x.start x.end i.ID i.time i.val
1:    1       5     7    1      6    20
2:    1       4     7    1      6    20
3:    1       7    11    1     10    40