Create subsets based on a certain sequence of values

Viewed 120

I have a data frame like this:

df <- data.frame(x = c(0:20), y = c(50:70),
                 m = c(0, 0, 0, 0, -1, 0, 0, 1, 0, 0, -1, 0 ,0 , -1, 0, 0, 1, 0, 0, -1, 0))

I would like to create subsets defined by a sequence of values in column 'm':

A sequence should start and end with m == -1, and there has to be a 1 between the start and finish -1. Each subset then includes all rows between the start and end.

For example, one of the subsets from the data above would look like:

Subset1 <- data.frame(x = c(4:10), y = c(54:60), m = c(-1, 0, 0, 1, 0, 0, -1))
#    x  y  m
# 1  4 54 -1 # starts with -1
# 2  5 55  0
# 3  6 56  0
# 4  7 57  1 # contains a 1
# 5  8 58  0
# 6  9 59  0
# 7 10 60 -1 # ends with -1

I have been trying a lot and I can't figure out how to do it. I have tried with mapply or for loops, but always I'm stuck when it comes to set up the pattern, since both ends of the pattern are the same.

For instance, with mapply, I've done:

List_subsets <- mapply(function(i, j, z) df[i:j:z, , drop = FALSE], -1, 1, -1,
                       SIMPLIFY = FALSE)

But of course, I always get the

# error: In i:j:z : numerical expression has 3 elements: only the first used

Do you know if that's possible and could you help me out? I would really appreciate your input, since I'm very new to R and it's very challenging for me.

Thanks a lot in advance!

1 Answers

You can try this, Please let me know if its your desired outcome:

library(stringr)
pattrn <- data.frame(str_locate_all(paste0(df$m+1,collapse=''),'0[1]*?2[1]*?0')[[1]])
## str_locate_all will find all start and end of the pattern -1,1,-1
## to find -1, 1, -1 , I have added 1 to the column, this will remove the negative sign for correct capture of location
## so, the new pattern to be found is 0,2,0, to do this I concatenated the m column and try to find the 0, 2, 0 with regex mentioned
pattrn_rows <- Map(seq, from=pattrn$start, to=pattrn$end)
## converting to data.frame
lapply(pattrn_rows,function(x)df[x,])
## finally subsetting, this step will give the final result into two lists of dataframes

Output:

[[1]]
    x  y  m
5   4 54 -1
6   5 55  0
7   6 56  0
8   7 57  1
9   8 58  0
10  9 59  0
11 10 60 -1

[[2]]
    x  y  m
14 13 63 -1
15 14 64  0
16 15 65  0
17 16 66  1
18 17 67  0
19 18 68  0
20 19 69 -1
Related