首页 > 解决方案 > 按 data.table 中的日期范围和标识符有条件地选择多个项目

问题描述

我有一个data.table包含单元标识符、一个设置标识符和一个此设置对其有效的数据范围。我需要提取特定日期的特定单位标识符的设置。以下最小工作示例显示了我将如何获得结果。

library(data.table)
settingstable=data.table(UNITID=c(1,1,1,2,2,2,3,4,5,6,6),
                     STARTDATE=as.POSIXct(c("2018-01-01","2018-02-28","2018-06-01","2018-01-01","2018-04-01","2018-06-01","2018-01-01","2018-01-01","2018-01-01","2018-01-01","2018-05-01")),
                     ENDDATE=as.POSIXct(c("2018-02-28","2018-05-31","2018-12-31","2018-03-31","2018-05-31","2018-12-31","2018-12-31","2018-12-31","2018-12-31","2018-04-30","2018-12-31")),
                     SETTINGS=c(1,2,3,4,5,6,7,8,9,10,11))
selectunits=c(2,4,6)
selectdays=as.POSIXct(c("2018-04-02","2018-05-03","2018-02-01"))

resultsettings=NULL
for (i in 1:length(selectunits)) {
  resultsettings=rbind(resultsettings,settingstable[UNITID==selectunits[i] & STARTDATE <= selectdays[i] & ENDDATE >= selectdays[i],.(UNITID,SETTINGS)])
}

对于大型 data.tables 或大量单位和天,这将非常低效。我希望与的分组by=UNITID可以工作,但不幸的是,这是不可能的,因为以下会导致longer object length is not a multiple of shorter object length错误。

resultsettings=settingstable[UNITID %in% selectunits & STARTDATE <= selectdays & ENDDATE >= selectdays,.(UNITID,SETTINGS),by=UNITID]

如何改进我的代码以使其运行效率更高?

标签: rdata.tabledate-rangeposixct

解决方案


您可以使用非 equi 连接:

settingstable[.(u = selectunits, d = selectdays), 
  on=.(UNITID = u, STARTDATE <= d, ENDDATE >= d), 
  .(UNITID, SETTINGS)]

   UNITID SETTINGS
1:      2        5
2:      4        8
3:      6       10

语法是x[i, on=, j].

  • 该列表i = .(u = selectunits, d = selectdays)被视为一个表,要加入到x = settingstable.
  • 连接的工作原理是查找每一行(如果i根据xon=
  • j中,我们可以转换结果。(没有j,我们只会得到连接的表。)

如果您的on=条件产生多个匹配项,它们都将出现在结果中。如果他们没有留下任何匹配项,SETTINGS并且来自的其他列x将是 NA (尽管可以使用nomatch=参数进行调整)。


推荐阅读