R:匹配最近的日期(效率问题)

时间:2016-08-24 12:42:01

标签: r date data.table matching

dt1 <- data.table(x = c("a", "a", "b", "b", "c"),
                  y = c("2016-03-01", "2016-05-10", "2016-04-14", "2016-06-25", "2016-01-12"))

   x          y
1: a 2016-03-01
2: a 2016-05-10
3: b 2016-04-14
4: b 2016-06-25
5: c 2016-01-12

dt2 <- data.table(x = c("a", "b", "b", "a"),
                  y = c("2016-05-13", "2016-04-16", "2016-06-20", "2016-02-28"),
                  z = c("1", "1", "2", "3"))

   x          y z
1: a 2016-05-13 1
2: b 2016-04-16 1
3: b 2016-06-20 2
4: a 2016-02-28 3

close.match <- function(dt1x, dt1y, threshold <= 3){
  if(dt1x %in% dt2$x){
    if(abs(as.numeric(as.Date(dt1y) - as.Date(dt2[x == dt1x][which.min(abs(as.Date(y) - as.Date(dt1y))),y]))) < threshold){
      return(dt2[x == dt1x][which.min(abs(as.Date(y) - as.Date(dt1y))),z])
    } else {
      "unknown"
    }
  } else {
    "unknown"
  }
}

dt1[,z:=dt1[,close.match(x,y),by=1:nrow(dt1)][,V1]]

   x          y       z
1: a 2016-03-01       3
2: a 2016-05-10       1
3: b 2016-04-14       1
4: b 2016-06-25 unknown
5: c 2016-01-12 unknown

想法是每个dt1有两个事件dt2y,时间戳x,每个x可以有多个条目,有不同的时间戳。如果匹配z的两个事件在3天之内发生,则预期输出是将dt1列添加到dt2$z,其值为x。否则返回“未知”。

上面的代码可以正常运行。但问题是矢量化 - 效率极低。希望找到有关如何以更有效的方式解决此类问题的任何想法。

2 个答案:

答案 0 :(得分:4)

如果使用current development version of data.table, v1.9.7,则可以使用新的条件连接功能,如下所示:

# v1.9.7+
dt1[dt2, z := i.z, on=.(x, start<=y, end>=y)]

此步骤是在将y列转换为Date并将startend仅添加到dt1之后。

FR, #1639直接为on参数提供表达式,以便完成整个任务,如下所示:

dt1[dt2, z := i.z, on=.(x, y-3<=y, y+3>=y)]

我会看看我是否可以加快速度。

答案 1 :(得分:0)

感谢David Arenburg,我想出的是:

dt1 <- data.table(x = c("a", "a", "b", "b", "c"),
                  y = c("2016-03-01", "2016-05-10", "2016-04-14", "2016-06-25", "2016-01-12"))

dt2 <- data.table(x = c("a", "b", "b", "a"),
                  y = c("2016-05-13", "2016-04-16", "2016-06-20", "2016-02-28"),
                  z = c("1", "1", "2", "3"))

dt1[,y:=as.Date(y)]
dt2[,y:=as.Date(y)]

dt1[,start:=y-3]
dt1[,end:=y+3]

dt2[,start:=y]
dt2[,end:=y]

setkey(dt2, start, end)

dt1 <- foverlaps(dt1, dt2, type="any")
dt1 <- dt1[,.(x = i.x, y = i.y, z)]
dt1[is.na(z),z:="unknown"]
dt1

   x          y       z
1: a 2016-03-01       3
2: a 2016-05-10       1
3: b 2016-04-14       1
4: b 2016-06-25 unknown
5: c 2016-01-12 unknown
编辑:好的,虽然这有效。它有点爆炸&#34;爆炸&#34;在大型数据集上,相当快地达到RAM限制。还需要一些改进。

EDIT2:setkey应该看起来像setkey(dt2, x, start, end)。否则,它将只查找数据集之间所有可能的时间间隔重叠,而不指定匹配变量。两个数据集上的条目超过100k,确保它过分了。