Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add rows with increased and decreased value in groups

Tags:

dataframe

r

dplyr

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?

like image 255
Adamm Avatar asked Dec 31 '25 21:12

Adamm


2 Answers

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
like image 194
ThomasIsCoding Avatar answered Jan 02 '26 12:01

ThomasIsCoding


Ok, I think I got it:

df %>%
  mutate(B_plus_one = B + 1,
         B_minus_one = B - 1) %>%
  bind_rows(., mutate(., B = B_plus_one)) %>%
  bind_rows(., mutate(., B = B_minus_one)) %>%
  select(-B_plus_one, -B_minus_one) %>%
  arrange(B) %>%
  unique()

   A  B
1  A  1
3  A  2
4  A  3
5  A  4
7  A  5
8  A  6
9  C  7
11 C  8
12 C  9
13 D 11
15 D 12
16 D 13
17 E 14
19 E 15
20 E 16
21 F 17
23 F 18
24 F 19
like image 42
Adamm Avatar answered Jan 02 '26 13:01

Adamm



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!