6

順序付けされたデータがラベル付けされて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 だけのダミー列を追加できます。

4

3 に答える 3

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
于 2013-03-05T19:08:57.003 に答える
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
于 2013-03-05T18:51:04.397 に答える
3

これは、ジョシュとアナンダのソリューションを組み合わせたものです。その中で、RLEを使用して、ジョシュが答えた方法を生成します。

t <- rle(DT$name)
t <- t$lengths[t$values == "a"]
DT[, cd := rep(t, t+1)]
DT[, cd:=max(.I) - .I, by=cd]

さらに良い:常に1つしかないという事実を利用してb(またはここで仮定すると)、これをより適切に行うことができます:

t <- rle(DT$name)
t <- t$lengths[t$values == "a"]
DT[, cd := rev(sequence(rev(t+1)))-1]

編集: OP のコメントから、複数のb可能性があり、そのような場合はすべてb0であることは明らかなよう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
于 2013-03-05T19:19:06.727 に答える