嗨,我很难区分两次特定事件何时发生在我的数据中。举例来说,假设我有3种类型的事件-a,b,c-每个事件在3个周期内都有效。
我想创建一个活动事件的周期系列,其中任何事件更改都将替换前一个事件,但是如果当前事件重复发生,它将重新开始。这是一些代码来说明:
a1 <- data.table(
c(1, 4, 7, 8),
c("a", "a", "c", "d")
)
a2 <- data.table(
c(1, 7, 8),
c("a", "c", "d")
)
b <- data.table(
seq(1, 8)
)
setkey(a1, V1)
setkey(a2, V1)
setkey(b, V1)
a1[b, roll = 2]
a2[b, roll = 2]
正如您在a1上看到的那样,我得到了事件类型为a的消息,而我没有得到有关事件实际上在何处重复的大量信息。理想情况下,我希望我的参加者能够对活动进行如下限定:
data.table(
c(1:8),
c("a", "a", "a", "a", "a", "a", "c", "d"),
event = c(1, 0, 0, 1, 0, 0, 1, 1)
)
有什么想法吗?谢谢!!!
答案 0 :(得分:4)
使用rleid
形成每个组,将向量1,0,0的长度重复为每个组的.N。
k <- 3 # restart after this number of events that are the same
one.zeros <- rep(1:0, c(1, k-1)) # length k vector. For k=3, c(1,0,0)
DT[, V3 := rep(one.zeros, length = .N), by = rleid(V2)]
给予:
> DT
V1 V2 V3
1: 1 a 1
2: 2 a 0
3: 3 a 0
4: 4 a 1
5: 5 a 0
6: 6 a 0
7: 7 c 1
8: 8 c 0
9: 9 d 1
输入DT
为:
library(data.table)
DT <- data.table(1:9, c("a", "a", "a", "a", "a", "a", "c", "c", "d"))
答案 1 :(得分:3)
@GaborGrothendieck答案的另一种形式:
DT[, v := 0L]
DT[(rowid(rleid(V2)) - 1L) %% 3 == 0, v := 1L][]
V1 V2 v
1: 1 a 1
2: 2 a 0
3: 3 a 0
4: 4 a 1
5: 5 a 0
6: 6 a 0
7: 7 c 1
8: 8 c 0
9: 9 d 1
这只是对每个rowid
组内的rleid
(1,2,3 ...)进行算术。
答案 2 :(得分:2)
您可以检查联接期间键(示例中的V1
)是否匹配:
a1[b, .(V2 = x.V2, event = isTRUE(x.V1 == i.V1)), roll = 2, by = .EACHI]
V1 V2 event
1: 1 a TRUE
2: 2 a FALSE
3: 3 a FALSE
4: 4 a TRUE
5: 5 a FALSE
6: 6 a FALSE
7: 7 c TRUE
8: 8 d TRUE
a2[b, .(V2 = x.V2, event = isTRUE(x.V1 == i.V1)), roll = 2, by = .EACHI]
V1 V2 event
1: 1 a TRUE
2: 2 a FALSE
3: 3 a FALSE
4: 4 <NA> FALSE
5: 5 <NA> FALSE
6: 6 <NA> FALSE
7: 7 c TRUE
8: 8 d TRUE
考虑到此答案中的评论:
set.seed(5438L)
n <- 1e5
a <- data.table(
sample(2 * n, n, replace = FALSE),
sample(c("a", "b", "c"), n, replace = TRUE),
key = "V1"
)
b <- data.table(1:(2 * n), key = "V1")
library(microbenchmark)
microbenchmark(
during = a[b, c(.SD, event = isTRUE(x.V1 == i.V1)), roll = 2, by = .EACHI],
after = a[b, roll = 2][a, event := !is.na(i.V1), on = "V1"],
times = 30L
)
Unit: milliseconds
expr min lq mean median uq max neval cld
during 767.49338 771.49878 795.02283 776.20243 787.96382 964.11575 30 b
after 26.14068 26.46543 28.58425 27.51831 29.73552 37.36052 30 a
因此,在这种情况下,IceCreamToucan的答案可能更好。
答案 3 :(得分:0)
我不确定我是否完全理解OP在此问题背后的意图,但我相信可以选择无需加入即可解决。
如果我理解正确,那么目标是扩展事件列表
V1 V2 1: 1 a 2: 4 a 3: 7 c 4: 8 d
进入一系列活动事件
V1 V2 event 1: 1 a 1 2: 2 a 0 3: 3 a 0 4: 4 a 1 5: 5 a 0 6: 6 a 0 7: 7 c 1 8: 8 d 1
在输入数据表中,V1
表示发生V2
类型的事件时的时间索引。因此,我们可以重复V2
的每个值直到下一个事件。通过将event
中给出的位置与时间索引序列进行比较来创建a1$V1
列:
a1[, .(1:max(V1), rep(V2, c(diff(V1), 1)), event = +(1:max(V1) %in% V1))]
V1 V2 event 1: 1 a 1 2: 2 a 0 3: 3 a 0 4: 4 a 1 5: 5 a 0 6: 6 a 0 7: 7 c 1 8: 8 d 1
(请注意,1:max(V1) %in% V1
是逻辑类型,+(1:max(V1) %in% V1)
将其强制为整数。)
此外,有两种变体可以返回相同的结果,但性能可能有所不同(未进行基准测试):
a1[, .(1:max(V1), rep(V2, c(diff(V1), 1)), event = replace(rep(0L, max(V1)), V1, 1L))]
使用replace()
创建event
列。
a1[, .(1:max(V1), rep(V2, c(diff(V1), 1)), event = 0L)][a1$V1, event := 1L][]
初始化event
列,但在后续步骤中有选择地更新它。