R - 识别连续序列

4
我有一个拥有107635行和三列的大文件,分别是主题、感兴趣区域(ROIs)和试验编号。ROIs可以是A、B、C、D、E、F。
我想要的是只保留那些在ROI列中有连续的B、C、D序列的试验,而且是第一次出现B时。不管B、C和D出现多少次都没关系。
在下面的示例中,我可以保留ntrial 78和201,因为第一次出现B后面跟着C和D。
但是,我需要删除ntrial 10和400。在试验10中,B、C和D不是连续的。在试验400中,第一次出现B时,B后面没有跟着C和D。
对于输出,我只需要一列,每行表示要保留的试验值为1,要删除的试验对应的行值为0。
有没有建议可以创建一个可以自动化该过程的代码,而不必检查每个试验?
非常感谢!
subject ROI ntrial output
sbj05   A   78     1
sbj05   A   78     1
sbj05   A   78     1
sbj05   A   78     1
sbj05   A   78     1
sbj05   A   78     1
sbj05   B   78     1
sbj05   B   78     1
sbj05   C   78     1
sbj05   D   78     1
sbj05   E   78     1
sbj05   E   78     1
sbj05   E   78     1
sbj05   A   201    1
sbj05   A   201    1
sbj05   A   201    1
sbj05   A   201    1
sbj05   A   201    1
sbj05   B   201    1
sbj05   C   201    1
sbj05   D   201    1
sbj05   E   201    1
sbj05   E   201    1
sbj05   E   201    1
sbj05   F   201    1
sbj05   F   201    1
sbj05   A   10     0
sbj05   A   10     0
sbj05   A   10     0
sbj05   A   10     0
sbj05   B   10     0
sbj05   A   10     0
sbj05   C   10     0
sbj05   D   10     0
sbj05   E   10     0
sbj05   E   10     0
sbj05   A   400    0
sbj05   A   400    0
sbj05   A   400    0
sbj05   B   400    0
sbj05   A   400    0
sbj05   B   400    0
sbj05   C   400    0
sbj05   C   400    0
sbj05   C   400    0
sbj05   D   400    0
sbj05   E   400    0
sbj05   E   400    0
sbj05   D   400    0

2
在第78次尝试中,它是“B B C D”,因此它不是首先出现的B后跟C D。 - akrun
1
请提供期望的输出,因为您的描述有些令人困惑。 - David Arenburg
1
@DavidArenburg,我包括了我想要获得的输出列。 - dede
1
@Vlo 这并没有考虑到 BCD 出现在第一次出现 B 之后的情况。 - akrun
如果其中一个答案对您有用,请考虑接受该答案。这将为未来的读者提供有关解决方案价值的线索。请参阅此帮助页面:当有人回答我的问题时我该怎么做? - Jaap
显示剩余6条评论
3个回答

4
这里尝试使用data.tablestringi来解决问题。
首先,我定义了一些辅助函数,帮助我检测每个组中第一个B的出现,并验证它们是否后跟正确的序列。
Myfunc <- function(x) {
               which(x == "B")[1L] == 
               stri_locate_first_regex(paste(x, collapse = ""), 'B*CD')[, 1L]
              } 

然后,实现就很直接了。
library(data.table)
library(stringi)
setDT(df)[, if(Myfunc(ROI)) .SD, by = .(subject, ntrial)]
#     subject ntrial ROI
#  1:   sbj05     78   A
#  2:   sbj05     78   A
#  3:   sbj05     78   A
#  4:   sbj05     78   A
#  5:   sbj05     78   A
#  6:   sbj05     78   A
#  7:   sbj05     78   B
#  8:   sbj05     78   B
#  9:   sbj05     78   C
# 10:   sbj05     78   D
# 11:   sbj05     78   E
# 12:   sbj05     78   E
# 13:   sbj05     78   E
# 14:   sbj05    201   A
# 15:   sbj05    201   A
# 16:   sbj05    201   A
# 17:   sbj05    201   A
# 18:   sbj05    201   A
# 19:   sbj05    201   B
# 20:   sbj05    201   C
# 21:   sbj05    201   D
# 22:   sbj05    201   E
# 23:   sbj05    201   E
# 24:   sbj05    201   E
# 25:   sbj05    201   F
# 26:   sbj05    201   F

或者,如果你只想要额外一列,你可以这样做。
setDT(df)[, output := +Myfunc(ROI), by = .(subject, ntrial)]

如果我们不是使用“B”、“C”和“D”,而是使用类似于“_target1”、“_target2”、“_target3”这样的字母字符串,该如何使用您的解决方案?在这些字符串中,每个观察值的第一部分不同,但第二部分相同(例如,abcdsgf_target1、hjgjkfkgkr_target1、jjjjdsds_target2、ljkg_target3、hascj_target3)。 - dede
我已经不记得原来的问题是什么了,但是为了提取这些字符串,你可以简单地使用类似于 sub(".*_", "", ROI)(未经测试)的东西,然后相应地调整代码。 - David Arenburg

1
这里是另一个:

idx <- sapply(split(df, df$ntrial), function(x) { 
  B <- with(rle(x$ROI == "B"),  sum(lengths[seq(which.max(values))]))
  all(x$ROI[B:(B+2)] == c("B", "C", "D"))
})
subset(df, ntrial %in% names(which(idx)))

0

使用matchrlebase R方法:

df$ output <- +as.logical(ave(as.character(df$ROI), df$ntrial, FUN=function(x) {rle(x[match("B",x):length(x)])$values[2] == "C"}))
#     subject ROI ntrial output
# 1    sbj05   A     78      1
# 2    sbj05   A     78      1
# 3    sbj05   A     78      1
# 4    sbj05   A     78      1
# 5    sbj05   A     78      1
# 6    sbj05   A     78      1
# 7    sbj05   B     78      1
# 8    sbj05   B     78      1
# 9    sbj05   C     78      1
# 10   sbj05   D     78      1
# 11   sbj05   E     78      1
# 12   sbj05   E     78      1
# 13   sbj05   E     78      1
# 14   sbj05   A    201      1
# 15   sbj05   A    201      1
# 16   sbj05   A    201      1
# 17   sbj05   A    201      1
# 18   sbj05   A    201      1
# 19   sbj05   B    201      1
# 20   sbj05   C    201      1
# 21   sbj05   D    201      1
# 22   sbj05   E    201      1
# 23   sbj05   E    201      1
# 24   sbj05   E    201      1
# 25   sbj05   F    201      1
# 26   sbj05   F    201      1
# 27   sbj05   A     10      0
# 28   sbj05   A     10      0
# 29   sbj05   A     10      0
# 30   sbj05   A     10      0
# 31   sbj05   B     10      0
# 32   sbj05   A     10      0
# 33   sbj05   C     10      0
# 34   sbj05   D     10      0
# 35   sbj05   E     10      0
# 36   sbj05   E     10      0
# 37   sbj05   A    400      0
# 38   sbj05   A    400      0
# 39   sbj05   A    400      0
# 40   sbj05   B    400      0
# 41   sbj05   A    400      0
# 42   sbj05   B    400      0
# 43   sbj05   C    400      0
# 44   sbj05   C    400      0
# 45   sbj05   C    400      0
# 46   sbj05   D    400      0
# 47   sbj05   E    400      0
# 48   sbj05   E    400      0
# 49   sbj05   D    400      0

那些未对齐的列一直让我感到烦恼。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接