2016-05-12 4 views
1

Angenommen, ich habe zwei Datenrahmen,findet die kürzeste Zeitdifferenz zwischen zwei Datenrahmen

df1 

id  time1 
1   2016-04-07 21:39:10 
1   2016-04-05 11:19:17 
2   2016-04-03 10:58:25 
2   2016-04-02 21:39:10 

df2 

id  time2 
1   2016-04-07 21:39:11 
1   2016-04-05 11:19:18 
1   2016-04-06 21:39:11 
1   2016-04-04 11:19:18 
2   2016-04-03 10:58:26 
2   2016-04-02 21:39:11 
2   2016-04-04 10:58:26 
2   2016-04-05 21:39:11 

ich für jeden Eintrag in df1 finden will, die kürzeste Zeitdifferenz in df2. Angenommen, wir nehmen den ersten Eintrag, es hat id1, also möchte ich df2 durchlaufen, nach id 1 filtern, dann den Zeitunterschied zwischen einem Eintrag von df1 und den restlichen Einträgen von df2 prüfen und die kürzeste Differenz finden und den entsprechenden Eintrag holen . Meine Beispielausgabe soll

id  time     time2     diff(in secs) 
1   2016-04-07 21:39:10 2016-04-07 21:39:10  1 
1   2016-04-05 11:19:17 2016-04-05 11:19:17  1 
2   2016-04-03 10:58:25 2016-04-03 10:58:25  1 
2   2016-04-02 21:39:10 2016-04-02 21:39:10  1 

folgende ist mein Versuch,

for(i in unique(df1$id)){ 
    temp1 = df1[df1$id == i,] 
    temp2 = df2[df2$id == i,] 
    for(j in unique(df1$time1){ 
    for(k in unique(df2$time2){ 
     diff = abs(df1$time1[j] - df2$time2[k] 
     print(diff)}}} 

Ich bin nicht in der Lage, nachdem diese Fortschritte, viele Fehler zu bekommen. Kann mir jemand helfen, das zu korrigieren? Kann ein besserer Weg vorgeschlagen werden, dies zu tun? Jede Hilfe wäre willkommen.

Update:

Reproduzierbare Daten:

df1 <- data.frame(
     id = c(1,1,2,2), 
     time1 = c('2016-04-07 21:39:10', '2016-04-05 11:19:17', '2016-04-03 10:58:25', '2016-04-02 21:39:10') 
    ) 

    df2 <- data.frame(
     id = c(1,1,1,1,2,2,2,2), 
     time2 = c('2016-04-07 21:39:11', '2016-04-05 11:19:18','2016-04-07 21:39:11', '2016-04-05 11:19:18', '2016-04-03 10:58:26', '2016-04-02 21:39:11','2016-04-03 10:58:26', '2016-04-02 21:39:11') 
    ) 

df1$time1 = as.POSIXct(df1$time1) 
df2$time2 = as.POSIXct(df2$time2) 
+0

Können Sie bitte den Code hinzufügen zu erzeugen 'df1' und' df2' – Divi

+0

tun, um die 'ID's Materie überhaupt? ? klingt wie der kürzeste Unterschied innerhalb 'id' – jaimedash

+0

@jaimedash ja zusammen mit den entsprechenden Zeiten – haimen

Antwort

2

Sie können diese dplyr mit erreichen. Grundsätzlich ist die Idee, da wir einen Eintrag erstellen wollen, werden wir jedem Element in df1 eine neue ID zuweisen (in diesem Fall habe ich es gerade als rowname bezeichnet).

Danach interessiert uns nur, die beiden Datenrahmen auf der id zu verbinden und sie basierend auf der minimalen absoluten Differenz zu filtern.

library(dplyr) 

df1$time1 <- as.POSIXct(as.character(df1$time1)) 
df2$time2 <- as.POSIXct(as.character(df2$time2)) 

df1 %>% 
    add_rownames("rowname") %>% 
    left_join(df2, "id") %>% 
    mutate(diff=time2-time1) %>% 
    group_by(rowname) %>% 
    filter(min(abs(diff)) == abs(diff)) %>% 
    distinct 

Das ist mein Ausgang:

Source: local data frame [4 x 5] 
Groups: rowname [4] 

    rowname id    time1    time2 diff 
    (chr) (dbl)    (time)    (time) (dfft) 
1  1  1 2016-04-07 21:39:10 2016-04-07 21:39:11 1 secs 
2  2  1 2016-04-05 11:19:17 2016-04-05 11:19:18 1 secs 
3  3  2 2016-04-03 10:58:25 2016-04-03 10:58:26 1 secs 
4  4  2 2016-04-02 21:39:10 2016-04-02 21:39:11 1 secs  
+0

Vielen Dank!Es funktionierte – haimen

1

Sie auch diese in der Basis R. tun können Zufallsdaten (nützlich) zu erzeugen, ich geliehen und eine nette Funktion von elsewhere on StackOverflow bearbeitet:

latemail <- function(N, st="2011/01/01", et="2016/12/31") { 
    st <- as.POSIXct(as.Date(st)) 
    et <- as.POSIXct(as.Date(et)) 
    dt <- as.numeric(difftime(et,st,unit="sec")) 
    ev <- sort(runif(N, 0, dt)) 
    return(st + ev) 
} 
df1 <- data.frame(id=c(1,1,2,2), time1=latemail(4)) 
df2 <- data.frame(id=c(rep(1,4), rep(2,4)), time2=latemail(8)) 

Und dann können Sie Ihre Antwort in zwei Linien erreicht werden:

shortest <- sapply(df1$time1, function(x) which(abs(df2$time2 - x) == min(abs(df2$time2 - x)))) 
cbind(df1, df2[shortest,]) 
Ausgabe

:

id    time1 id    time2 
1 2011-10-08 02:00:21 1 2011-08-17 18:07:47 
1 2012-05-06 17:49:03 1 2012-09-04 19:52:40 
2 2013-10-29 13:14:51 1 2012-10-29 20:09:31 
2 2016-06-17 19:23:43 2 2015-11-24 02:07:15 
0

Wenn Sie mit data.table arbeiten:

library(data.table) 
df1 <- data.table(
    id = c(1,1,2,2), 
    time1 = c('2016-04-07 21:39:10', '2016-04-05 11:19:17', '2016-04-03 10:58:25', '2016-04-02 21:39:10') 
) 

df2 <- data.table(
    id = c(1,1,1,1,2,2,2,2), 
    time2 = c('2016-04-07 21:39:11', '2016-04-05 11:19:18','2016-04-07 21:39:11', '2016-04-05 11:19:18', '2016-04-03 10:58:26', '2016-04-02 21:39:11','2016-04-03 10:58:26', '2016-04-02 21:39:11') 
) 

df1$time1 = as.POSIXct(df1$time1) 
df2$time2 = as.POSIXct(df2$time2) 

res <- df1[df2, .(time1, time2), by = .EACHI, on = "id"][, diff:= abs(time2 -time1)] 
setkey(res, id, time1, diff) 
res <- res[, row := seq_along(.I), by = .(id, time1)][row == 1]