具有中断的增量序列

the*_*ide 7 r run-length-encoding dplyr data.table

我有一个重复序列的数据集TRUE,我希望根据某些条件标记 - 依据id序列的增量值.A FALSE打破TRUEs 的序列,并且第一个FALSE打破任何给定序列的序列TRUE应包括在该序列中.FALSEs之间TRUE的连续s 是无关紧要的,标记为0.

例如:

> test
   id logical sequence
1   1    TRUE        1
2   1    TRUE        1
3   1   FALSE        1
4   1    TRUE        2
5   1    TRUE        2
6   1   FALSE        2
7   1    TRUE        3
8   2    TRUE        1
9   2    TRUE        1
10  2    TRUE        1
11  2   FALSE        1
12  2    TRUE        2
13  2    TRUE        2
14  2    TRUE        2
15  3   FALSE        0
16  3   FALSE        0
17  3   FALSE        0
18  3    TRUE        1
19  3   FALSE        1
20  3    TRUE        2
21  3   FALSE        2
22  3   FALSE        0
23  3   FALSE        0
24  3   FALSE        0
25  3    TRUE        3
Run Code Online (Sandbox Code Playgroud)

等等.我考虑过使用rle()哪种产品

> rle(test$logical)
Run Length Encoding
  lengths: int [1:13] 2 1 2 1 4 1 3 3 1 1 ...
  values : logi [1:13] TRUE FALSE TRUE FALSE TRUE FALSE ...
Run Code Online (Sandbox Code Playgroud)

但我不知道如何将其映射到数据框架上.有关如何解决这个问题的任何建议?

以下是示例数据:

> dput(test)
structure(list(id = c(1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 
2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), logical = c(TRUE, TRUE, 
FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, 
TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, 
FALSE, FALSE, TRUE)), .Names = c("id", "logical"), class = "data.frame", row.names = c(NA, 
-25L))
Run Code Online (Sandbox Code Playgroud)

Jaa*_*aap 5

纯粹的data.table解决方案:

# load the 'data.table'-package & convert 'test' to a data.table with 'setDT'
library(data.table)
setDT(test)

# calculate the new sequence
test[, new_seq := (rleid(logical) - !logical) * !(!logical & !shift(logical, fill = FALSE)), by = id
     ][new_seq != 0, new_seq := rleid(new_seq), by = id][]
Run Code Online (Sandbox Code Playgroud)

这使:

    id logical new_seq
 1:  1    TRUE       1
 2:  1    TRUE       1
 3:  1   FALSE       1
 4:  1    TRUE       2
 5:  1    TRUE       2
 6:  1   FALSE       2
 7:  1    TRUE       3
 8:  2    TRUE       1
 9:  2    TRUE       1
10:  2    TRUE       1
11:  2   FALSE       1
12:  2    TRUE       2
13:  2    TRUE       2
14:  2    TRUE       2
15:  3   FALSE       0
16:  3   FALSE       0
17:  3   FALSE       0
18:  3    TRUE       1
19:  3   FALSE       1
20:  3    TRUE       2
21:  3   FALSE       2
22:  3   FALSE       0
23:  3   FALSE       0
24:  3   FALSE       0
25:  3    TRUE       3
Run Code Online (Sandbox Code Playgroud)

这是做什么的:

  • rleid(logical) - !logical创建一个数字游程长度id和1where logical等于的子句FALSE
  • 然后将前一步骤的结果乘以结果!(!logical & !shift(logical, fill = FALSE)),该结果是除了序列中的第一个之外的连续值的TRUE/ FALSE向量.FALSEFALSE
  • 最后,我们为只有new_seq不等于的行创建一个新的游程长度id 0并得到你想要的结果.

稍微改进的替代方案(如评论中@jogo所建议的):

test[, new_seq := (rleid(logical) - !logical) * (logical | shift(logical, fill = FALSE)), by = id
     ][new_seq != 0, new_seq := rleid(new_seq), by = id][]
Run Code Online (Sandbox Code Playgroud)