Home > Back-end >  Group sequence based on positive to its negative value shift
Group sequence based on positive to its negative value shift

Time:12-02

I have the following dataframe called df (dput below):

   value
1     -4
2     -3
3     -2
4     -1
5      0
6      1
7      2
8      3
9     -3
10    -2
11    -1
12     0
13     1
14     2
15     3
16    -3
17    -2
18    -1
19     0
20     1
21     2
22    -2
23    -1
24     0
25     1
26     2
27     3
28     4

I would like to group the sequence column 'value' based on when a positive value becomes its negative value, when that happens it was a group. So row 8 has value 3 and row 9 has value -3 which means the positive value changed in its negative value so all rows to row 8 are a group. The shift also happens by row 15 and 16 and so on. Here is the desired output:

   value group
1     -4     1
2     -3     1
3     -2     1
4     -1     1
5      0     1
6      1     1
7      2     1
8      3     1
9     -3     2
10    -2     2
11    -1     2
12     0     2
13     1     2
14     2     2
15     3     2
16    -3     3
17    -2     3
18    -1     3
19     0     3
20     1     3
21     2     3
22    -2     4
23    -1     4
24     0     4
25     1     4
26     2     4
27     3     4
28     4     4

So I was wondering if anyone knows how to group this sequence based on a positive to its negative value shift?


dput of df:

df <- structure(list(value = c(-4, -3, -2, -1, 0, 1, 2, 3, -3, -2, 
-1, 0, 1, 2, 3, -3, -2, -1, 0, 1, 2, -2, -1, 0, 1, 2, 3, 4)), class = "data.frame", row.names = c(NA, 
-28L))

CodePudding user response:

Edit: Updated the answer to stabilise the output.

I think you could use

library(dplyr)

df %>% 
  group_by(grp = cumsum(coalesce(value == -lag(value, n = 1), TRUE)))

This returns

# A tibble: 28 x 2
# Groups:   grp [4]
   value   grp
   <dbl> <int>
 1    -4     1
 2    -3     1
 3    -2     1
 4    -1     1
 5     0     1
 6     1     1
 7     2     1
 8     3     1
 9    -3     2
10    -2     2
11    -1     2
12     0     2
13     1     2
14     2     2
15     3     2
16    -3     3
17    -2     3
18    -1     3
19     0     3
20     1     3
21     2     3
22    -2     4
23    -1     4
24     0     4
25     1     4
26     2     4
27     3     4
28     4     4

I used group_by to do the grouping, replace it with mutate if you just need a new column.

  • Related