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

How to combine R dataframes based constraints on a time column

我有两个 R table,每个都有一个用户列表和一个与他们采取特定操作的时间相对应的时间戳。

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

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

我想做的是加入两个 table 并以 table 结束,该 table 与 df1 中的用户匹配,时间戳最接近df2,只要 df2 中的时间戳发生在 之后 df1.

中的时间戳

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

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

我一直在努力解决这个问题。作为额外的复杂层,如果有一个参数控制时间 window 以允许匹配(即仅加入来自 df2 的行,如果它在 X 内,我会喜欢它df1 分钟),但这实际上是主要问题的次要问题。

第 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 部分 - 时间 Window

如果您想要 window 的时间来进行匹配,您可以在 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 select 什么,都将在 .

内完成

这是一个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