2015-06-04 20 views
8

Ho il seguente problema: dato un set di intervalli non sovrapposti in un data.table, riportare gli intervalli tra gli intervalli.Trovare intervalli tra intervalli utilizzando data.table

Ho implementato questo una volta in SQL, tuttavia sto lottando con data.table a causa della mancanza di una funzione di guida o funzione di ritardo. Per completezza, ho here il codice SQL. So che la funzionalità è stata implementata in data.table versione 1.9.5. come da changelog. Quindi è possibile con data.table senza fare un sacco di fusioni e senza una funzione lag o lead?

In linea di principio, non sono completamente contrario all'uso di unioni (anche se unite) purché le prestazioni non ne risentano. Penso che questo abbia un'implementazione semplice, ma non riesco a capire come "ottenere" l'orario di fine precedente per essere l'ora di inizio del mio gap table.

Ad esempio:

# The numbers represent seconds from 1970-01-01 01:00:01 
dat <- structure(
    list(ID = c(1L, 1L, 1L, 2L, 2L, 2L), 
     stime = structure(c(as.POSIXct("2014-01-15 08:00:00"), 
          as.POSIXct("2014-01-15 11:00:00"), 
          as.POSIXct("2014-01-16 11:30:00"), 
          as.POSIXct("2014-01-15 09:30:00"), 
          as.POSIXct("2014-01-15 12:30:00"), 
          as.POSIXct("2014-01-15 13:30:00") 
          ), 
         class = c("POSIXct", "POSIXt"), tzone = ""), 
     etime = structure(c(as.POSIXct("2014-01-15 10:30:00"), 
          as.POSIXct("2014-01-15 12:00:00"), 
          as.POSIXct("2014-01-16 13:00:00"), 
          as.POSIXct("2014-01-15 11:00:00"), 
          as.POSIXct("2014-01-15 12:45:00"), 
          as.POSIXct("2014-01-15 14:30:00") 
          ), 
         class = c("POSIXct", "POSIXt"), tzone = "") 
), 
    .Names = c("ID", "stime", "etime"), 
    sorted = c("ID", "stime", "etime"), 
    class = c("data.table", "data.frame"), 
    row.names = c(NA,-6L) 
) 

dat <- data.table(dat) 

Questo si traduce in:

ID    stime    etime 
1 2014-01-15 10:30:00 2014-01-15 11:00:00 
1 2014-01-15 12:00:00 2014-01-16 11:30:00 
2 2014-01-15 11:00:00 2014-01-15 12:30:00 
2 2014-01-15 12:45:00 2014-01-15 13:30:00 

Avviso: le lacune sono segnalati in modo uniforme giorni.

+2

Non ti manca una fila qui o mi manca qualcosa? –

+3

nota a margine: 'dat <- data.table (dat)' è uno spreco di memoria .. usa invece 'setDT (dat)'. – Arun

+2

Penso che questo possa essere fatto con piccole modifiche alla risposta di @ eddi nella tua precedente Q. – Arun

risposta

5

Una variante di risposta di David, probabilmente un po 'meno efficiente, ma più semplice di digitare:

setkey(dat, stime)[, .(stime=etime[-.N], etime=stime[-1]), by=ID] 

produce:

ID    stime    etime 
1: 1 2014-01-15 10:30:00 2014-01-15 11:00:00 
2: 1 2014-01-15 12:00:00 2014-01-16 11:30:00 
3: 2 2014-01-15 11:00:00 2014-01-15 12:30:00 
4: 2 2014-01-15 12:45:00 2014-01-15 13:30:00 

setkey è solo per assicurarsi tabella è ordinata col tempo.

5

Se non mi manca qualcosa, ti manca una riga nell'output desiderato, quindi ecco il mio tentativo di utilizzare shift dalla versione di sviluppo come hai menzionato.

library(data.table) ## v >= 1.9.5 
indx <- dat[, .I[-.N], by = ID]$V1 
dat[, .(ID, stimes = etime, etime = shift(stime, type = "lead"))][indx] 
res 
# ID    stime    etime 
# 1: 1 2014-01-15 10:30:00 2014-01-15 11:00:00 
# 2: 1 2014-01-15 12:00:00 2014-01-16 11:30:00 
# 3: 2 2014-01-15 11:00:00 2014-01-15 12:30:00 
# 4: 2 2014-01-15 12:45:00 2014-01-15 13:30:00