我有两个数据帧: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)
非常感谢您的帮助!
答案 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)
使用data.table的非等额联接功能:
# 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 df1
与df2
一起加入。通过使用on = .(id, time >= start, time <= end)
,您可以加入id
的完全匹配项,同时time
必须从start
等于或等于df1
并等于或小于等于从end
到df1
。time
(df1
和start
)的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