使用dplyr根据不同数据框中的条件过滤行数据框

时间:2018-10-25 09:54:54

标签: r dplyr

我有两个数据帧:df1和df2(请参见下面的示例)。 df1包含每个字符ID的数字开始和结束值。 df2每个字符ID包含多个事件,包括一个数字时间值。

library(dplyr)

df1 <- data_frame(id = c("A", "B"),
                  start = c(2, 3),
                  end = c(5, 9))

df2 <- data_frame(id = c(rep("A", 4), rep("B", 4)),
                  time = c(1, 3, 5, 8, 2, 3, 4, 10),
                  keep = c(FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE))

我试图根据时间值等于或介于df1中每个id的起始值和结束值之间的时间,使用dplyr过滤df2中的事件。因此,过滤器为“ df2 $ time> = df1 $ start和df2 $ time <= df1 $ end”,应分别为每个id执行。我添加了一个逻辑列“ keep”,以显示要保留在df2中的行。

如何为每个ID执行此过滤器?最好使用dplyr。这应该是最终结果:

df2 %>%
  filter(keep == TRUE)

非常感谢您的帮助!

3 个答案:

答案 0 :(得分:3)

使用dplyr这样的事情怎么办?

  df1 %>% 
  left_join(df2) %>%                       #joining to have one dataset
  filter(time <= end, time >= start) %>%   # filter, you can use <, > in case
  select(-c(2,3))                          # remove useless column if necessary

# A tibble: 4 x 3
  id     time keep 
  <chr> <dbl> <lgl>
1 A         3 TRUE 
2 A         5 TRUE 
3 B         3 TRUE 
4 B         4 TRUE 

答案 1 :(得分:2)

使用的非等额联接功能:

# load the package and convert the dataframes to data.tables
library(data.table)
setDT(df1)
setDT(df2)

# non-equi join
df2[df1
    , on = .(id, time >= start, time <= end)
    , .(id, time = x.time)]

给出:

   id time
1:  A    3
2:  A    5
3:  B    3
4:  B    4

这是什么:

  • setDT()将data.frame转换为data.table
  • 您将df1df2一起加入。通过使用on = .(id, time >= start, time <= end),您可以加入id的完全匹配项,同时time必须从start等于或等于df1并等于或小于等于从enddf1
  • 进行非等额联接时,将从timedf1start)的end列返回为{{1} }和time用于满足连接条件的情况(see also here)。要了解我的意思,您可以执行time
  • 通过使用df2[df1, on = .(id, time >= start, time <= end)],您可以返回所需的列。 .(id, time = x.time)指的是x-data.table中的x.time列,time

答案 2 :(得分:0)

这也有效

df2$start <- df1[match(df2$id, df1$id),"start"]
df2$end <- df1[match(df2$id, df1$id),"end"]
df2$keep <- df2$time>df2$start& df2$time<df2$end
result <- df2 %>%  filter(keep)
result