2016-08-24 6 views
1
dt1 <- data.table(x = c("a", "a", "b", "b", "c"), 
        y = c("2016-03-01", "2016-05-10", "2016-04-14", "2016-06-25", "2016-01-12")) 

    x   y 
1: a 2016-03-01 
2: a 2016-05-10 
3: b 2016-04-14 
4: b 2016-06-25 
5: c 2016-01-12 

dt2 <- data.table(x = c("a", "b", "b", "a"), 
        y = c("2016-05-13", "2016-04-16", "2016-06-20", "2016-02-28"), 
        z = c("1", "1", "2", "3")) 

    x   y z 
1: a 2016-05-13 1 
2: b 2016-04-16 1 
3: b 2016-06-20 2 
4: a 2016-02-28 3 

close.match <- function(dt1x, dt1y, threshold <= 3){ 
    if(dt1x %in% dt2$x){ 
    if(abs(as.numeric(as.Date(dt1y) - as.Date(dt2[x == dt1x][which.min(abs(as.Date(y) - as.Date(dt1y))),y]))) < threshold){ 
     return(dt2[x == dt1x][which.min(abs(as.Date(y) - as.Date(dt1y))),z]) 
    } else { 
     "unknown" 
    } 
    } else { 
    "unknown" 
    } 
} 

dt1[,z:=dt1[,close.match(x,y),by=1:nrow(dt1)][,V1]] 

    x   y  z 
1: a 2016-03-01  3 
2: a 2016-05-10  1 
3: b 2016-04-14  1 
4: b 2016-06-25 unknown 
5: c 2016-01-12 unknown 

Idee ist, dass es zwei Ereignisse dt1 und dt2 mit Zeitstempel y für jeden x, kann es für jeden x, mit unterschiedlichen Zeitstempeln mehr als ein Eintrag sein. Die erwartete Ausgabe besteht darin, die Spalte z zu dt1 mit einem Wert von dt2$z hinzuzufügen, wenn zwei Ereignisse für die Übereinstimmung x innerhalb von 3 Tagen aufeinander folgen. Andernfalls "unbekannt" zurückgeben.R: Matching am nächsten Tag (Effizienz Ausgabe)

Der obige Code funktioniert und macht genau das. Aber das Problem ist die Vektorisierung - es ist extrem ineffizient. In der Hoffnung, irgendwelche Ideen zu finden, wie man diese Art von Problemen auf effizientere Weise lösen kann.

+0

Verwenden Sie 'ifelse', um zu vektorisieren? – aichao

+0

Warum läuft 'asDate' by row ?? Und du machst es jedes Mal 6 Mal? Das erste, was Sie tun sollten, ist 'dt1 [, y: = as.IDate (y)]; dt2 [, y: = as.IDate (y)] 'vor jeder Berechnung. Zweitens würde ich hier einen rollenden Join versuchen –

+1

Vielleicht zwei rollende Joins. Etwas wie 'indx1 <- dt2 [dt1, ein = c (x =" x ", y =" y "), roll = -3, was = WAHR]; indx2 <- dt2 [dt1, ein = c (x = "x", y = "y"), Rolle = 3, was = WAHR]; dt1 [! is.na (indx1), z: = dt2 [na.mit (indx1), z]]; dt1 [! is.na (indx2), z: = dt2 [na.mit (indx2), z]]; dt1' könnte dir ein paar Ideen geben. Oder vielleicht versuchen Sie 'foverlaps' –

Antwort

4

Wenn Sie die current development version of data.table, v1.9.7 verwenden, dann können Sie das neue bedingte verbindet Funktion verwenden, wie folgt:

# v1.9.7+ 
dt1[dt2, z := i.z, on=.(x, start<=y, end>=y)] 

Dieser Schritt kommt nach beiden y Spalten Date Umwandlung und das Hinzufügen von start und end zu dt1 allein.


Es gibt eine FR, #1639 direkt zum Ausdruck, on Argument zu liefern, so dass die gesamte Aufgabe erreicht werden kann, wie folgt:

dt1[dt2, z := i.z, on=.(x, y-3<=y, y+3>=y)] 

Ich werde sehen, ob ich es bis beschleunigen kann.

+0

Gibt es eine Schätzung darüber, wann 1.9.7 Cran weitergeht? Ich würde lieber 1.9.6 verwenden, da ich meinen Code teile und lieber Nicht-Dev-Versionen verwende. –

+0

Revisited dieses Problem als "data.table" 1.9.8 ging auf Cran. Es scheint sehr gut zu funktionieren. –

0

Dank David Arenburg, hier ist, was ich kam mit:

dt1 <- data.table(x = c("a", "a", "b", "b", "c"), 
        y = c("2016-03-01", "2016-05-10", "2016-04-14", "2016-06-25", "2016-01-12")) 

dt2 <- data.table(x = c("a", "b", "b", "a"), 
        y = c("2016-05-13", "2016-04-16", "2016-06-20", "2016-02-28"), 
        z = c("1", "1", "2", "3")) 

dt1[,y:=as.Date(y)] 
dt2[,y:=as.Date(y)] 

dt1[,start:=y-3] 
dt1[,end:=y+3] 

dt2[,start:=y] 
dt2[,end:=y] 

setkey(dt2, start, end) 

dt1 <- foverlaps(dt1, dt2, type="any") 
dt1 <- dt1[,.(x = i.x, y = i.y, z)] 
dt1[is.na(z),z:="unknown"] 
dt1 

    x   y  z 
1: a 2016-03-01  3 
2: a 2016-05-10  1 
3: b 2016-04-14  1 
4: b 2016-06-25 unknown 
5: c 2016-01-12 unknown 

EDIT: Okay, während das funktioniert. Es "explodiert" auf großen Datenmengen und erreicht RAM-Grenzen ziemlich schnell. Noch einige Verbesserungen erforderlich.

EDIT2: setkey sollte wie setkey(dt2, x, start, end) aussehen. Andernfalls sucht es nur nach ALLEN möglichen Zeitintervall-Überlappungen zwischen Datensätzen, ohne die passende Variable anzugeben. Mit über 100.000 Einträgen in beiden Datensätzen wurde sichergestellt, dass es über Bord ging.

+0

Haben Sie versucht, Mu Rolling Join-Lösung überhaupt? Es sollte sowohl effizient Speicher als auch Geschwindigkeit sein. Außerdem wird Aruns Lösung noch besser sein. –

+0

Arbeit ist passiert. Konnte nicht mehr Zeit mit der Erforschung verschiedener Ansätze verbringen. Sobald ich etwas Zeit finde, werde ich meine Antwort mit rollenden Beiträgen aktualisieren. Danke nochmal, du hast richtige Hinweise gegeben und das Problem ist gelöst. –

+0

Sie brauchen nicht wirklich zu recherchieren ... Versuchen Sie einfach meinen Code in dem Kommentar wie es ist und sehen Sie, wie lange es dauert Ihre Daten. –

Verwandte Themen