我有data.table
有序数据,我想添加一个列,告诉我有多少记录,直到我找到一个重置倒计时的“特殊”记录。
例如:
DT = data.table(idx = c(1,3,3,4,6,7,7,8,9),
name = c("a", "a", "a", "b", "a", "a", "b", "a", "b"))
setkey(DT, idx)
#manually add the answer
DT[, countdown := c(3,2,1,0,2,1,0,1,0)]
给予
> DT
idx name countdown
1: 1 a 3
2: 3 a 2
3: 3 a 1
4: 4 b 0
5: 6 a 2
6: 7 a 1
7: 7 b 0
8: 8 a 1
9: 9 b 0
查看倒计时列如何告诉我有多少行,直到一行称为“b”。 问题是如何在代码中创建该列。
请注意,密钥间隔不均匀,可能包含重复项(因此在解决问题时不是很有用)。一般来说,非b名称可能不同,但如果解决方案需要,我可以添加一个只有True / False的虚拟列。
答案 0 :(得分:7)
这是另一个想法:
## Create groups that end at each occurrence of "b"
DT[, cd:=0L]
DT[name=="b", cd:=1L]
DT[, cd:=rev(cumsum(rev(cd)))]
## Count down within them
DT[, cd:=max(.I) - .I, by=cd]
# idx name cd
# 1: 1 a 3
# 2: 3 a 2
# 3: 3 a 1
# 4: 4 b 0
# 5: 6 a 2
# 6: 7 a 1
# 7: 7 b 0
# 8: 8 a 1
# 9: 9 b 0
答案 1 :(得分:6)
我确信(或者至少有希望)会生成纯粹的“data.table”解决方案,但与此同时,您可以使用rle
。在这种情况下,您有兴趣撤消倒计时,因此我们将在继续之前使用rev
来反转“名称”值。
output <- sequence(rle(rev(DT$name))$lengths)
makezero <- cumsum(rle(rev(DT$name))$lengths)[c(TRUE, FALSE)]
output[makezero] <- 0
DT[, countdown := rev(output)]
DT
# idx name countdown
# 1: 1 a 3
# 2: 3 a 2
# 3: 3 a 1
# 4: 4 b 0
# 5: 6 a 2
# 6: 7 a 1
# 7: 7 b 0
# 8: 8 a 1
# 9: 9 b 0
答案 2 :(得分:3)
这是Josh和Ananda的解决方案的混合,我使用RLE来生成Josh给出答案的方式:
t <- rle(DT$name)
t <- t$lengths[t$values == "a"]
DT[, cd := rep(t, t+1)]
DT[, cd:=max(.I) - .I, by=cd]
更好:利用只有b
总是(或假设在这里)的事实,你可以更好地做到这一点:
t <- rle(DT$name)
t <- t$lengths[t$values == "a"]
DT[, cd := rev(sequence(rev(t+1)))-1]
编辑:根据OP的评论,似乎很明显可能有多个b
,在这种情况下,所有b
都应为0.第一步这样做是为了创建b
在每个连续a
之后结束的组。
DT <- data.table(idx=sample(10), name=c("a","a","a","b","b","a","a","b","a","b"))
t <- rle(DT$name)
val <- cumsum(t$lengths)[t$values == "b"]
DT[, grp := rep(seq(val), c(val[1], diff(val)))]
DT[, val := c(rev(seq_len(sum(name == "a"))),
rep(0, sum(name == "b"))), by = grp]
# idx name grp val
# 1: 1 a 1 3
# 2: 7 a 1 2
# 3: 9 a 1 1
# 4: 4 b 1 0
# 5: 2 b 1 0
# 6: 8 a 2 2
# 7: 6 a 2 1
# 8: 3 b 2 0
# 9: 10 a 3 1
# 10: 5 b 3 0