2016-05-12 68 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最短的时间差。假设我们取第一个入口,它有id 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)}}} 

我不能在此之后的进步,越来越多的错误。有谁能帮我纠正这个问题吗?可能会建议一个更有效的方法来做到这一点?任何帮助,将不胜感激。

更新:

重放数据:

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中为每个元素分配一个新的ID(在这种情况下,我只称它为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]