使用data.table将区间转换为R中每个工作日的每小时持续时间

时间:2015-06-22 11:39:26

标签: r data.table

我有以下问题:

假设我们有:

 Idx        ID      StartTime          EndTime
  1:         1 2014-01-01 02:20:00 2014-01-01 03:42:00
  2:         1 2014-01-01 14:51:00 2014-01-01 16:44:00

注意:未给出 Idx ,但我只是将其添加到表格视图中。

现在我们看到ID = 1的人正在使用计算机,时间是2:20到3:42。现在我想做的是将这个间隔转换为一组代表小时和工作日的变量以及这些时期的持续时间。

 Idx        ID Monday-0:00 Monday-1:00 ... Wednesday-2:00 Wednesday-3:00
  1:         1                                  40             42

对于第二行,我们将

 Idx        ID Monday-0:00 Monday-1:00 ... Wednesday-14:00 Wednesday-15:00  Wednesday-16:00
  2:         1                                  9             60                  44

现在问题当然是从第二行可以看出它可以跨越多个小时。

我想这样做每行,我想知道如果没有太多的计算工作并使用data.table,这是否可行?

PS:间隔也可能超过一天。

1 个答案:

答案 0 :(得分:1)

library(data.table)
library(lubridate)
#produce sample data
DT<-data.table(idx=1:100,ID=rep(1:20,5), StartTime=runif(100,60*60,60*60*365)+ymd('2014-01-01'))
DT[,EndTime:=StartTime+runif(1,60,60*60*8)]

#make fake start and end dates with same day of week and time but all within a single calendar week
DT[,fakestart:=as.numeric(difftime(StartTime,ymd('1970-01-01'),units="days"))%%7*60*60*24+ymd('1970-01-01')]
DT[,fakeend:=as.numeric(difftime(EndTime,ymd('1970-01-01'),units="days"))%%7*60*60*24+ymd('1970-01-01')]
setkey(DT,fakestart,fakeend)
#check that weekdays line up
nrow(DT[weekdays(EndTime)==weekdays(fakeend)])
nrow(DT[weekdays(StartTime)==weekdays(fakestart)])
#both are 100 so we're good.

#check that fakeend > fakestart
DT[fakeend<fakestart]
#uh-oh some ends are earlier than starts, let's add 7 days to those ends
DT[fakeend<fakestart,fakeend:=fakeend+days(7)]


#make data.table with all possible labels
DTin<-data.table(start=seq(from=ymd('1970-01-01'),to=DT[,floor_date(max(fakeend),"hour")],by=as.difftime(hours(1))))
DTin[,end:=start+hours(1)]
DTin[,label:=paste0(format(start,format="%A-%H:00"),' ',format(end,format="%A-%H:00"))]

#set key and use new foverlaps feature of data.table which merges by interval
setkey(DT,fakestart,fakeend)
setkey(DTin,start,end)
DTout<-foverlaps(DT,DTin,type="any")

#compute duration in each interval
DTout[,dur:=60-pmax(0,difftime(fakestart,start,unit="mins"))-pmax(0,difftime(end,fakeend,unit="mins"))]

#cast all the rows up to columns for final result
castout<-dcast.data.table(DTout,idx+ID~label,value.var="dur",fill=0)