如何在时间列上组合基于 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
我有两个 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