2016-05-12 1 views
1

Пусть у меня есть два dataframes,найти кратчайшее разницу во времени между двумя dataframes

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 

Я хочу найти для каждой записи в df1, кратчайшим разница во времени в df2. Предположим, что мы берем первую запись, она имеет идентификатор 1, поэтому я хочу перебрать df2, фильтр для id 1, а затем проверить разницу во времени между одной записью df1 и остальными вхождениями df2 и найти кратчайшую разницу и получить соответствующую запись , Мой выход образец должен быть

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 

следующее моя попытка,

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)}}} 

Я не в состоянии прогрессировать после этого, получив много ошибок. Может ли кто-нибудь помочь мне в исправлении этого? Можно предложить более эффективный способ сделать это? Любая помощь будет оценена по достоинству.

Update:

воспроизводимое данные:

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

Можете ли вы добавить код для создания '' df1' и df2' – Divi

+0

сделать 'id's дело вообще? ? звучит как кратчайшая разница внутри 'id' – jaimedash

+0

@jaimedash да вместе с соответствующими моментами – haimen

ответ

2

Вы можете добиться этого с помощью dplyr. В принципе, идея состоит в том, что мы хотим создать запись, которую мы присвоим каждому элементу в df1 новый идентификатор (в данном случае я просто назвал его rowname).

После этого все, что нас интересует, объединяет два кадра данных на id и фильтрует их на основе минимальной абсолютной разницы.

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 

Это мой выход:

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

Большое спасибо!Это сработало – haimen

1

Вы также можете сделать это в базе R. Для того, чтобы генерировать случайные даты (полезный), я позаимствовал и редактируются хорошую функцию от elsewhere on StackOverflow:

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)) 

И тогда ваш ответ может быть достигнуто в две строки:

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

Выход:

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

Если вы работаете с data.table:

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]