如何在时间列上组合基于R数据帧的约束



我有两个R表,每个表都有一个用户列表和一个与他们执行某个操作的时间相对应的时间戳。

这两个表中的第一个(df1)有一个详尽的用户列表,用户将有多个具有不同时间戳的行。

第二个(df2)将有一个更有限的用户列表,但用户将以不同的时间戳多次出现在表中。

我想做的是将这两个表连接起来,最终得到一个与df1中的用户和df2中最接近的时间戳相匹配的表,只要df2中的时间戳发生在df1中的时间标签之后。

例如,如果我有两个表,如:

df1 <- data.frame(c(1,1,2,3), as.POSIXct(c('2016-12-01 08:53:20', '2016-12-01 12:45:47', '2016-12-01 15:34:54', '2016-12-01 00:49:50')))
names(df1) <- c('user', 'time')
df2 <- data.frame(c(1,1,3), as.POSIXct(c('2016-12-01 07:11:01', '2016-   12-01 11:50:11', '2016-12-01 01:19:10')))
names(df2) <- c('user', 'time')

给我们:

> df1
user                time
1    1 2016-12-01 08:53:20
2    1 2016-12-01 12:45:47
3    2 2016-12-01 15:34:54
4    3 2016-12-01 00:49:50
> df2
user                time
1    1 2016-12-01 07:11:01
2    1 2016-12-01 11:50:11
3    3 2016-12-01 01:19:10

我希望得到的输出看起来像:

user              time_1                 time_2
1   2016-12-01 08:53:20    2016-12-01 11:50:11
1   2016-12-01 12:45:47    NA
2   2016-12-01 15:34:54    NA
3   2016-12-01 00:49:50    2016-12-01 01:19:10

我在争取加入的路上遇到了麻烦。作为一个额外的复杂性层,如果有一个参数控制时间窗口以允许匹配(即,如果在df1X分钟内,则仅加入df2的行),我会很高兴,但实际上这是主要问题的次要问题。

第1部分-原始问题

您问题的第一部分可以使用sqldf软件包来回答。

library(sqldf)
df3 <- sqldf("SELECT * FROM df1 a 
LEFT JOIN df2 b ON a.time < b.time 
AND a.user = b.user")[,c(1:2, 4)]
#rename to match OP post
names(df3) <- c("user", "time_1", "time_2")
> df3
user              time_1              time_2
1    1 2016-12-01 08:53:20 2016-12-01 11:50:11
2    1 2016-12-01 12:45:47                <NA>
3    2 2016-12-01 15:34:54                <NA>
4    3 2016-12-01 00:49:50 2016-12-01 01:19:10

第2部分-时间窗口

如果你想要一个时间窗口来允许比赛,你可以在SQL语句中减去秒,如下所示:

df3 <- sqldf("SELECT * FROM df1 a 
LEFT JOIN df2 b ON a.time < (b.time - 10000)
AND a.user = b.user")[,c(1:2, 4)]
> df3
user                time              time.1
1    1 2016-12-01 08:53:20 2016-12-01 11:50:11
2    1 2016-12-01 12:45:47                <NA>
3    2 2016-12-01 15:34:54                <NA>
4    3 2016-12-01 00:49:50                <NA>

请注意,无论您从b.time中选择什么,都将在秒内

这是一个data.table解决方案。

# load data.table and make cast data.frames as data.tables
library(data.table)
setDT(df1)
setDT(df2)
# add time variables, perform join and removing merging time variable
dfDone <- df2[, time2 := time][df1[, time1 := time],
on=.(user, time > time)][, time:= NULL]
dfDone
user               time2               time1
1:    1 2016-12-01 11:50:11 2016-12-01 08:53:20
2:    1                <NA> 2016-12-01 12:45:47
3:    2                <NA> 2016-12-01 15:34:54
4:    3 2016-12-01 01:19:10 2016-12-01 00:49:50

如果您想订购列,可以使用setcolorder

setcolorder(dfDone, c("user", "time1", "time2"))
dfDone
user               time1               time2
1:    1 2016-12-01 08:53:20 2016-12-01 11:50:11
2:    1 2016-12-01 12:45:47                <NA>
3:    2 2016-12-01 15:34:54                <NA>
4:    3 2016-12-01 00:49:50 2016-12-01 01:19:10

最新更新