2017-09-13 1 views
0

Ich habe eine data.table mit Zeitreihen von stündlichen Beobachtungen von verschiedenen Standorten (Standorte). Es gibt Lücken - fehlende Stunden - in jeder Sequenz. Ich möchte die Stundenfolge für jeden Standort ausfüllen, so dass jede Sequenz für jede Stunde eine Zeile enthält (obwohl Daten fehlen, NA).Wie machen Sie kontinuierliche Zeitfolgen innerhalb von Gruppen in der data.table?

Beispiel Daten:

library(data.table) 
library(lubridate) 

DT <- data.table(site = rep(LETTERS[1:2], each = 3), 
       date = ymd_h(c("2017080101", "2017080103", "2017080105", 
           "2017080103", "2017080105", "2017080107")), 
       # x = c(1.1, 1.2, 1.3, 2.1, 2.2, 2.3, 3.1, 3.2, 3.3), 
       x = c(1.1, 1.2, 1.3, 2.1, 2.2, 2.3), 
       key = c("site", "date")) 
DT 
# site    date x 
# 1: A 2017-08-01 01:00:00 1.1 
# 2: A 2017-08-01 03:00:00 1.2 
# 3: A 2017-08-01 05:00:00 1.3 
# 4: B 2017-08-01 03:00:00 2.1 
# 5: B 2017-08-01 05:00:00 2.2 
# 6: B 2017-08-01 07:00:00 2.3 

Das gewünschte Ergebnis DT2 alle Stunden enthalten würde zwischen dem ersten (Minimum) Datum und die letzte (maximal) Datum für jeden Standort, mit x fehlt, wo die neuen Zeilen eingefügt :

# site    date x 
# 1: A 2017-08-01 01:00:00 1.1 
# 2: A 2017-08-01 02:00:00 NA 
# 3: A 2017-08-01 03:00:00 1.2 
# 4: A 2017-08-01 04:00:00 NA 
# 5: A 2017-08-01 05:00:00 1.3 
# 6: B 2017-08-01 03:00:00 2.1 
# 7: B 2017-08-01 04:00:00 NA 
# 8: B 2017-08-01 05:00:00 2.2 
# 9: B 2017-08-01 06:00:00 NA 
#10: B 2017-08-01 07:00:00 2.3 

ich habe versucht, DT mit einem Datum Reihenfolge von min(date) und max(date) aufgebaut zu verbinden. Dies ist in der richtigen Richtung, aber der Datumsbereich ist über alle Standorte, anstatt für jede einzelne Website, die in Reihen hat fehlende Stelle gefüllt, und die Sortierreihenfolge (key) ist falsch:

DT[.(seq(from = min(date), to = max(date), by = "hour")), 
    .SD, on="date"] 
# site    date x 
# 1: A 2017-08-01 01:00:00 1.1 
# 2: NA 2017-08-01 02:00:00 NA 
# 3: A 2017-08-01 03:00:00 1.2 
# 4: B 2017-08-01 03:00:00 2.1 
# 5: NA 2017-08-01 04:00:00 NA 
# 6: A 2017-08-01 05:00:00 1.3 
# 7: B 2017-08-01 05:00:00 2.2 
# 8: NA 2017-08-01 06:00:00 NA 
# 9: B 2017-08-01 07:00:00 2.3 

So natürlich ich versuchte Hinzufügen by = site:

DT[.(seq(from = min(date), to = max(date), by = "hour")), 
    .SD, on="date", by=.(site)] 
# site    date x 
# 1: A 2017-08-01 01:00:00 1.1 
# 2: A 2017-08-01 03:00:00 1.2 
# 3: A 2017-08-01 05:00:00 1.3 
# 4: NA    <NA> NA 
# 5: B 2017-08-01 03:00:00 2.1 
# 6: B 2017-08-01 05:00:00 2.2 
# 7: B 2017-08-01 07:00:00 2.3 

Aber das funktioniert auch nicht. Kann jemand die richtige data.table Formulierung vorschlagen, um das gewünschte ausgefüllte DT2 oben gezeigt zu geben?

+1

Warum es nicht funktioniert: 'DT [i, j, von]' gelesen wird "Filter von' i'; Gruppe von 'by'; dann tun' j'. " Sie versuchen, gruppierte Operationen in "i" zu machen. – Frank

+1

Danke @Frank. Ich kann jetzt sehen, dass ich die 'seq()' in 'j' setzen musste und dann das resultierende' DT' in 'i' verwende. –

Antwort

2
library(data.table) 
library(lubridate) 
setDT(DT) 
test <- DT[, .(date = seq(min(date), max(date), by = 'hour')), by = 
       'site'] 
DT <- merge(test, DT, by = c('site', 'date'), all.x = TRUE) 


DT 
    site    date x 
1: A 2017-08-01 01:00:00 1.1 
2: A 2017-08-01 02:00:00 NA 
3: A 2017-08-01 03:00:00 1.2 
4: A 2017-08-01 04:00:00 NA 
5: A 2017-08-01 05:00:00 1.3 
6: B 2017-08-01 03:00:00 2.1 
7: B 2017-08-01 04:00:00 NA 
8: B 2017-08-01 05:00:00 2.2 
9: B 2017-08-01 06:00:00 NA 
10: B 2017-08-01 07:00:00 2.3 
+2

Mehr Standard in den Daten.Tabelle: 'DT [test, on = Namen (Test)]' – Frank

+1

@Frank Ja, Sie haben Recht, tut mir leid, ich bin nicht beendigt Vertraut mit 'data.table' :) – Wen

+0

Dank @Wen. Gute Antwort. Aber ich bevorzuge das 'merge()' mit der 'data.table' Join-Syntax, die die Vorteile von' data.table's Optimierungen (falls vorhanden) nutzen kann. –

1

Danke an Frank und Wen, dass sie mich auf den richtigen Weg gebracht haben. Ich fand eine kompakte data.table Lösung. Das Ergebnis DT2 wird auch vor Ort und Datum eingegeben, wie in der Eingabetabelle (was wünschenswert ist, obwohl ich dies im OP nicht angefordert habe). Dies ist eine Neuformulierung von Wens Lösung, in data.table Syntax, die ich nehme an, wird etwas effizienter auf großen Datensätzen.

DT2 <- DT[setkey(DT[, .(date = seq(from = min(date), to = max(date), 
         by = "hour")), by = site], site, date), ] 
DT2 
# site    date x 
# 1: A 2017-08-01 01:00:00 1.1 
# 2: A 2017-08-01 02:00:00 NA 
# 3: A 2017-08-01 03:00:00 1.2 
# 4: A 2017-08-01 04:00:00 NA 
# 5: A 2017-08-01 05:00:00 1.3 
# 6: B 2017-08-01 03:00:00 2.1 
# 7: B 2017-08-01 04:00:00 NA 
# 8: B 2017-08-01 05:00:00 2.2 
# 9: B 2017-08-01 06:00:00 NA 
#10: B 2017-08-01 07:00:00 2.3 
key(DT2) 
# [1] "site" "date" 

EDIT1: Wie Frank erwähnt, die on= Syntax kann auch verwendet werden. Die folgende DT3 Formulierung gibt die richtige Antwort, aber DT3 ist nicht codiert, während das DT2 Ergebnis codiert ist. Das bedeutet, dass ein 'extra' setkey() benötigt würde, wenn ein getastetes Ergebnis gewünscht wurde.

DT3 <- DT[DT[, .(date = seq(from = min(date), to = max(date), 
        by = "hour")), by = site], on = c("site", "date"), ] 
DT3 
# site    date x 
# 1: A 2017-08-01 01:00:00 1.1 
# 2: A 2017-08-01 02:00:00 NA 
# 3: A 2017-08-01 03:00:00 1.2 
# 4: A 2017-08-01 04:00:00 NA 
# 5: A 2017-08-01 05:00:00 1.3 
# 6: B 2017-08-01 03:00:00 2.1 
# 7: B 2017-08-01 04:00:00 NA 
# 8: B 2017-08-01 05:00:00 2.2 
# 9: B 2017-08-01 06:00:00 NA 
#10: B 2017-08-01 07:00:00 2.3 
key(DT3) 
# NULL 
all.equal(DT2, DT3) 
# [1] "Datasets has different keys. 'target': site, date. 'current' has no key." 
all.equal(DT2, DT3, check.attributes = FALSE) 
# [1] TRUE 

Gibt es eine Möglichkeit, den DT3 Ausdruck zu schreiben, einen Schlüssel Ergebnis zu liefern, die nicht ausdrücklich setkey() verwenden?

EDIT2: Franks Kommentar schlägt eine zusätzliche Formulierung DT4 mit keyby = .EACHI vor. In diesem Fall wird .SD als j eingefügt, was erforderlich ist, wenn by oder keyby verwendet wird. Dies gibt die richtige Antwort und das Ergebnis ist wie die DT2 Formel formuliert.

DT4 <- DT[DT[, .(date = seq(from = min(date), to = max(date), by = "hour")), 
      by = site], on = c("site", "date"), .SD, keyby = .EACHI] 
DT4 
# site    date x 
# 1: A 2017-08-01 01:00:00 1.1 
# 2: A 2017-08-01 02:00:00 NA 
# 3: A 2017-08-01 03:00:00 1.2 
# 4: A 2017-08-01 04:00:00 NA 
# 5: A 2017-08-01 05:00:00 1.3 
# 6: B 2017-08-01 03:00:00 2.1 
# 7: B 2017-08-01 04:00:00 NA 
# 8: B 2017-08-01 05:00:00 2.2 
# 9: B 2017-08-01 06:00:00 NA 
#10: B 2017-08-01 07:00:00 2.3 
key(DT4) 
# [1] "site" "date" 
identical(DT2, DT4) 
# [1] TRUE 
+0

Sieht gut aus. Fyi, 'on =' ist jetzt idiomatisch anstatt einen Schlüssel zu setzen, aus Gründen, die Arun hier erklärt: https://stackoverflow.com/a/20057411/ – Frank

+1

@Frank, ich habe auch die richtige Antwort mit 'on =' but Das Ergebnis wurde nicht eingegeben. Also habe ich den 'setkey()' Ansatz beibehalten. –

+0

Eine grobe Methode, um sie zu vergleichen: Ersetzen Sie ',]' durch ', .SD, keyby = .EACHI]'. Wenn Sie einen guten Grund haben, in diesem Fall einen Schlüssel zu haben, dann sollten Sie sich für ein 'keyon =' Argument (oder etwas) auf der Mailing-Liste oder dem Issue-Tracker aussprechen. – Frank

Verwandte Themen