dede
dede

Reputation: 1171

R - identify consecutive sequences

I have a big file with 107635 rows, and 3 columns: subject, regions of interest (ROIs), and number of the trial. The ROIs can be A, B, C, D, E, F. What I want to do is to keep only those trials where in the column ROI I have a consecutive sequence of B, C, D, the first time that B appears. It doesn't matter how many times B, C and D occur.

In the example below, I can keep ntrial 78 and 201, because the first time that B appeared was followed by C and D. However, I need to remove the ntrial 10 and 400. In the trial 10 B, C and D are not consecutive. In the trial 400 the first time that B appears, B is not followed by C and D.

For the output, I just need a column with a value of 1 for the trials to keep, in each row, and a value of 0 for the rows corresponding to the trials to remove.

Any suggestion on how to create a code that can automatise the procedure, without visually inspect each trial?

Many thanks!

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

Upvotes: 4

Views: 1795

Answers (3)

Pierre L
Pierre L

Reputation: 28441

A base R way with match and rle:

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

the columns not being aligned were bugging me

Upvotes: 0

David Arenburg
David Arenburg

Reputation: 92282

Here's an attempt using data.table and stringi

First, I'm defining some helper function that will help me detect first accurances of B per group and validate that they are followed by the correct sequence

Myfunc <- function(x) {
               which(x == "B")[1L] == 
               stri_locate_first_regex(paste(x, collapse = ""), 'B*CD')[, 1L]
              } 

Then, the implementation is straight forward

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

Or, if you just want an additional column you could do

setDT(df)[, output := +Myfunc(ROI), by = .(subject, ntrial)]

Upvotes: 4

lukeA
lukeA

Reputation: 54237

Here's another one:

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)))

Upvotes: 1

Related Questions