与this question类似,我想使用data.table
找到时间戳对之间重叠的持续时间。
这是我目前的代码:
library(data.table)
DT <- fread(
"stage,ID,date1,date2
1,A,2018-04-17 00:00:00,2018-04-17 01:00:00
1,B,2018-04-17 00:00:00,2018-04-17 00:20:00
1,C,2018-04-17 00:15:00,2018-04-17 01:00:00
2,B,2018-04-17 00:30:00,2018-04-17 01:10:00
2,D,2018-04-17 00:30:00,2018-04-17 00:50:00",
sep = ","
)
cols <- c("date1", "date2")
DT[, (cols) := lapply(.SD, as.POSIXct), .SDcols = cols]
breaks <- DT[, {
tmp <- unique(sort(c(date1, date2)))
.(start = head(tmp, -1L), end = tail(tmp, -1L))
}, by = stage]
result <- DT[breaks, on = .(stage, date1 <= start, date2 >= end), paste(ID, collapse = "+"),
by = .EACHI, allow.cartesian = T] %>%
mutate(lengthinseconds = as.numeric(difftime(date2, date1, units = "secs")))
返回:
stage date1 date2 V1 lengthinseconds
1 1 2018-04-17 00:00:00 2018-04-17 00:15:00 B+A 900
2 1 2018-04-17 00:15:00 2018-04-17 00:20:00 B+A+C 300
3 1 2018-04-17 00:20:00 2018-04-17 01:00:00 A+C 2400
4 2 2018-04-17 00:30:00 2018-04-17 00:50:00 D+B 1200
5 2 2018-04-17 00:50:00 2018-04-17 01:10:00 B 1200
但我想只返回用户对话框之间的重叠(即不超过两个重叠用户)。我可以想到实现这一点的几种方法,例如:
library(dplyr)
library(tidyr)
result %>%
filter(nchar(V1)==3) %>%
tidyr::separate(V1, c("ID1", "ID2"))
返回:
stage date1 date2 ID1 ID2 lengthinseconds
1 1 2018-04-17 00:00:00 2018-04-17 00:15:00 B A 900
2 1 2018-04-17 00:20:00 2018-04-17 01:00:00 A C 2400
3 2 2018-04-17 00:30:00 2018-04-17 00:50:00 D B 1200
但这似乎不够优雅,特别是在处理较长的ID
字符串时,每次重叠可能有数百ID
次。
理想情况下,我想知道是否有办法修改原始data.table
代码以直接返回此代码。
答案 0 :(得分:3)
另一种可能性:
DT[breaks, on = .(stage, date1 <= start, date2 >= end)
][, if (uniqueN(ID) == 2) .SD, by = .(stage, date1, date2)
][, dcast(.SD, stage + date1 + date2 ~ rowid(date1, prefix = 'ID'), value.var = 'ID')
][, lengthinseconds := as.numeric(difftime(date2, date1, units = "secs"))][]
给出:
stage date1 date2 ID1 ID2 lengthinseconds 1: 1 2018-04-17 00:00:00 2018-04-17 00:15:00 B A 900 2: 1 2018-04-17 00:20:00 2018-04-17 01:00:00 A C 2400 3: 2 2018-04-17 00:30:00 2018-04-17 00:50:00 D B 1200
答案 1 :(得分:2)
乍一看(并且忽略了性能方面的考虑),这只需要对OP代码进行一些小修改:
result <- DT[breaks, on = .(stage, date1 <= start, date2 >= end),
if (.N == 2L) paste(ID, collapse = "+"),
by = .EACHI, allow.cartesian = TRUE]
result
stage date1 date2 V1 1: 1 2018-04-17 00:00:00 2018-04-17 00:15:00 B+A 2: 1 2018-04-17 00:20:00 2018-04-17 01:00:00 A+C 3: 2 2018-04-17 00:30:00 2018-04-17 00:50:00 D+B
仅对于那些组,即时间范围,只有两个用户处于活动状态,才会创建结果行。
OP要求在单独的列中显示两个ID
以显示重叠的持续时间。另外,我建议将ID
排序。
result <- DT[breaks, on = .(stage, date1 <= start, date2 >= end),
if (.N == 2L) {
tmp <- sort(ID)
.(ID1 = tmp[1], ID2 = tmp[2], dur.in.sec = difftime(end, start, units = "secs"))
},
by = .EACHI, allow.cartesian = TRUE]
result
stage date1 date2 ID1 ID2 dur.in.sec 1: 1 2018-04-17 00:00:00 2018-04-17 00:15:00 A B 900 secs 2: 1 2018-04-17 00:20:00 2018-04-17 01:00:00 A C 2400 secs 3: 2 2018-04-17 00:30:00 2018-04-17 00:50:00 B D 1200 secs