Search code examples
rdataframedplyr

Add rows with increased and decreased value in groups


I have an example df:

df <- structure(list(A = c('A', 'B', 'C', 'D', 'E', 'F'), 
                     B = c(2, 5, 8, 12, 15, 18)), class = "data.frame", row.names = c(NA, -6L))

  A  B
1 A  2
2 B  5
3 C  8
4 D 12
5 E 15
6 F 18

I'd like to add rows with with value B increased and decreased by 1 in groups like this:

   A         B
 1 A         1
 2 A         2
 3 A         3
 4 B         4
 5 B         5
 6 B         6
 7 C         7
 8 C         8
 9 C         9
10 D        11
11 D        12
12 D        13
13 E        14
14 E        15
15 E        16
16 F        17
17 F        18
18 F        19

So I did something like this and it does the trick:

df %>%
  group_by(A) %>%
  complete(B = B + c(-1,1)) %>%
  arrange(B)

However my real data has... let's say duplicated groups:

df <- structure(list(A = c('A', 'A', 'C', 'D', 'E', 'F'), 
                     B = c(2, 5, 8, 12, 15, 18)), class = "data.frame", row.names = c(NA, -6L))
  A  B
1 A  2
2 A  5
3 C  8
4 D 12
5 E 15
6 F 18

And I still want to add 1 and -1 to each element in group leaving the original one and keeping the order in group:

A         B
1 A         1
2 A         2
3 A         3
4 A         4
5 A         5
6 A         6
7 C         7
8 C         8
9 C         9
10 D        11
11 D        12
12 D        13
13 E        14
14 E        15
15 E        16
16 F        17
17 F        18
18 F        19

My solution doesn't work no more giving:

   A         B
 1 A         1
 2 A         2
 3 A         5
 4 A         6
 5 C         7
 6 C         8
(...)

Could you please show me how can I modify my somple dplyr code?


Solution

  • You can use unnest like below

    df %>%
        mutate(B = list(B + (-1:1)), .by = A) %>%
        unnest(B)
    

    which gives

    # A tibble: 18 × 2
       A         B
       <chr> <dbl>
     1 A         1
     2 A         2
     3 A         3
     4 B         4
     5 B         5
     6 B         6
     7 C         7
     8 C         8
     9 C         9
    10 D        11
    11 D        12
    12 D        13
    13 E        14
    14 E        15
    15 E        16
    16 F        17
    17 F        18
    18 F        19