我有两个数据框x和y,其中包含id和日期的列。
id.x <- c(1, 2, 4, 5, 7, 8, 10)
date.x <- as.Date(c("2015-01-01", "2015-01-02", "2015-01-21", "2015-01-13", "2015-01-29", "2015-01-01", "2015-01-03"),format = "%Y-%m-%d")
x <- data.frame(id.x, date.x)
id.y <- c(1, 2, 3, 6, 7, 8, 9)
date.y <- as.Date(c("2015-01-03", "2015-01-29", "2015-01-22", "2015-01-13", "2015-01-29", "2014-12-31", "2015-01-03"), format = "%Y-%m-%d")
y <- data.frame(id.y, date.y)
我想通过匹配id和wether date将它们加入到新的数据帧z中。在date.x + 3天内发生,例如个人“1”在date.y =“2015-01-03”上发生事件“y”,该事件发生在日期x =“2015-01-01”的事件x的3天内。
答案 0 :(得分:2)
最近实现了data.table的开发版本v1.9.7
,其中非equi (或条件)连接,我们可以用简单(高效)的方式做到这一点..请参阅安装说明here。
require(data.table) # v1.9.7+
setDT(x)
setDT(y) ## convert both data.frames to data.tables by reference
x[, date.x.plus3 := date.x + 3L]
y[x, .(id.x, date.x, date.y=x.date.y),
on=.(id.y == id.x, date.y >= date.x, date.y <= date.x.plus3)]
# id.x date.x date.y
# 1: 1 2015-01-01 2015-01-03
# 2: 2 2015-01-02 <NA>
# 3: 4 2015-01-21 <NA>
# 4: 5 2015-01-13 <NA>
# 5: 7 2015-01-29 2015-01-29
# 6: 8 2015-01-01 <NA>
# 7: 10 2015-01-03 <NA>
连接虚拟列然后根据条件进行过滤的解决方案通常不可扩展(因为行数快速爆炸),循环遍历并为每行运行过滤条件的解决方案很慢,嗯,因为他们按行执行操作。
这个解决方案既不会,也不会直接执行条件连接,因此在运行时和内存方面都应该具有高性能。
答案 1 :(得分:1)
如果date.y&lt; = date.x + 3和date.y&gt; = date.x并且等于date.y,则可以创建一个ifelse语句,该语句创建一个等于date.x的向量。然后根据这个向量合并两个:
id.x <- c(1, 2, 4, 5, 7, 8, 10)
date.x <- as.Date(c("2015-01-01", "2015-01-02", "2015-01-21", "2015-01-13", "2015-01-29", "2015-01-01", "2015-01-03"),format = "%Y-%m-%d")
x <- cbind.data.frame(id.x, date.x)
id.y <- c(1, 2, 3, 6, 7, 8, 9)
date.y <- as.Date(c("2015-01-03", "2015-01-29", "2015-01-22", "2015-01-13", "2015-01-29", "2014-12-31", "2015-01-03"), format = "%Y-%m-%d")
y <- cbind.data.frame(id.y, date.y)
safe.ifelse <- function(cond, yes, no) structure(ifelse(cond, yes, no), class = class(yes))
match <- safe.ifelse(date.y <= date.x+3 & date.y >= date.x,
match <- date.x,
match <- date.y)
y$date.x <- match
names(y)[1] <- "id.x"
dplyr::left_join(x, y, by=c("id.x","date.x"))
id.x date.x date.y
1 1 2015-01-01 2015-01-03
2 2 2015-01-02 <NA>
3 4 2015-01-21 <NA>
4 5 2015-01-13 <NA>
5 7 2015-01-29 2015-01-29
6 8 2015-01-01 <NA>
7 10 2015-01-03 <NA>
我从这个post借用了 safe.ifelse 函数,因为基本ifelse语句导致数字向量而不是日期向量。
答案 2 :(得分:1)
使用y和x数据表的内连接,方法是将键设置为两个数据表的id,然后检查日期条件,最后提取真实数据。
library("data.table")
x <- as.data.table(x)
y <- as.data.table(y)
setkey(x, id.x)
setkey(y, id.y)
z <- y[x, nomatch = 0][, j = .(is_true = ((date.y <= date.x + 3) & (date.y > date.x)), id.y, date.x, date.y)][i = is_true == TRUE]
> z
is_true id.y date.x date.y
1: TRUE 1 2015-01-01 2015-01-03