在R data.table中将时间戳状态事件日志转换为运行时日志



我有一个大的记录时间戳的数据集,对应于状态变化(例如,灯开关翻转),看起来像这样:

library(data.table)
library(lubridate)
foo <- 
  data.table(ts = ymd_hms("2013-01-01 01:00:01",
                          "2013-01-01 05:34:34",
                          "2013-01-02 14:12:12",
                          "2013-01-02 20:01:00",
                          "2013-01-02 23:01:00",
                          "2013-01-03 03:00:00",
                          "2013-05-04 05:00:00"),
             state = c(1, 0, 1, 0, 0, 1, 0) )

我正在尝试(1)将状态日志的历史转换为以秒为单位的运行时间,(2)将这些转换为每日累积运行时间。大多数时候(但不是全部),连续的记录状态值是交替的。这是一个笨拙的开始,但它有点不足。

foo[, dif:=diff(ts)]
foo[state==1][, list(runtime = sum(dif)), .(floor_date(ts, "day"))]

特别地,当状态是"on"的时间超过午夜时,这种方法不够聪明,无法将事情分开,并且错误地报告超过一天的运行时间。同样,使用diff也不是那么智能,因为如果有连续的相同状态或NAs,它会犯错误。

有什么建议可以正确地解决运行时问题,并且对于大型数据集来说仍然是快速有效的?

应该可以。我尝试了不同的foo初始值,但仍然存在一些我没有考虑到的边缘情况。您需要注意的一件事是,如果您的实际数据有一个接受夏令时的时区,那么在制作数据时会中断。所有日期的表。您可以通过首先对UTC或GMT执行force_tz来解决这个问题(您可以稍后将其更改回来)。另一方面,如果你需要考虑一天的25小时或23小时,那么你需要有策略地将它们更改回你的时区。

#I'm using devel version of data.table which includes shift function for leading/lagging variables
foo[,(paste0("next",names(foo))):=shift(.SD,1,0,"lead")]
#shift with fill=NA produced an error for some reason this is workaround
foo[nrow(foo),`:=`(nextts=NA,nextstate=NA)]
#make data.table with every date from min ts to max ts
complete<-data.table(datestamp=seq(from=floor_date(foo[,min(ts)],unit="day"),to=ceiling_date(foo[,max(ts)],unit="day"),by="days"))
#make column for end of day
complete[,enddate:=datestamp+hours(23)+minutes(59)+seconds(59.999)]
#set keys and then do overlapping join
setkey(foo,ts,nextts)
setkey(complete,datestamp,enddate)
overlap<-foverlaps(foo[state==1],complete,type="any")
#compute run time for each row
overlap[,runtime:=as.numeric(difftime(pmin(datestamp+days(1),nextts),pmax(datestamp,ts),units="secs"))]
#summarize down to seconds per day
overlap[,list(runtime=sum(runtime)),by=datestamp]

最新更新