Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining and duplicating rows based on a condition

Tags:

r

dplyr

I'm searching for an elegant solution for combining, duplicating, and mutating rows based on a condition:

In my example, I would like to combine x = 1 and x = 2 and then duplicate these rows. Then mutate each subset back to their original classification.

Data

df <- tibble(x = c(1,1,1,2,2,2,3,4,5,6), 
         y = c(11,12,13,14,15,16,17,18,19,20), 
         z = c(21,22,23,24,25,26,27,28,29,30))
       x     y     z
   <dbl> <dbl> <dbl>
 1     1    11    21
 2     1    12    22
 3     1    13    23
 4     2    14    24
 5     2    15    25
 6     2    16    26
 7     3    17    27
 8     4    18    28
 9     5    19    29
10     6    20    30

Current Solution

Combine rows when x is in 1 or 2 and store them as 1

df <- df %>%
  mutate(x = ifelse(x %in% c(1,2), 1, x))

Filter for x is 1 and mutate to 2. Store this as a subset

df_temp <- df %>%
  filter(x == 1) %>%
  mutate(x = 2)

Bind the rows back

df <- rbind(df,df_temp)

Desired Output

       x     y     z
   <dbl> <dbl> <dbl>
 1     1    11    21
 2     1    12    22
 3     1    13    23
 4     1    14    24
 5     1    15    25
 6     1    16    26
 7     3    17    27
 8     4    18    28
 9     5    19    29
10     6    20    30
11     2    11    21
12     2    12    22
13     2    13    23
14     2    14    24
15     2    15    25
16     2    16    26

I think the first step can be skipped. separate_rows() may do the trick here if i combine them with a separator but i'd like to avoid this.

Looking for a dplyr solution.

EDIT 2:

If we simplify the data above to:

df <- tibble(x = c(1,1,2,2,2,3,4,5,6), 
             y = c(11,12,14,15,16,17,18,19,20), 
             z = c(21,22,24,25,26,27,28,29,30))

Where the number of rows of x = 1 and x = 2 are different. Filtering and reversing y and z no longer gives the correct solution.

Expected outcome

      x     y     z
   <dbl> <dbl> <dbl>
 1     1    11    21
 2     1    12    22
 3     1    14    24
 4     1    15    25
 5     1    16    26
 6     2    14    24
 7     2    15    25
 8     2    16    26
 9     2    11    21
10     2    12    22
11     3    17    27
12     4    18    28
13     5    19    29
14     6    20    30
like image 593
Ali Avatar asked Apr 17 '26 20:04

Ali


1 Answers

you can try

df %>% 
  full_join(filter(df, x %in% 1:2) %>% complete(x, y)) 
# A tibble: 5 x 2
      x     y
  <dbl> <dbl>
1     1     6
2     2     7
3     3     8
4     1     7
5     2     6

When including column z, one has to complete over the nested columns y & z like

df %>% 
  full_join(filter(df, x %in% 1:2) %>% 
              complete(x, nesting(y, z))) %>% 
  arrange(x)
# A tibble: 16 x 3
       x     y     z
   <dbl> <dbl> <dbl>
 1     1    11    21
 2     1    12    22
 3     1    13    23
 4     1    14    24
 5     1    15    25
 6     1    16    26
 7     2    14    24
 8     2    15    25
 9     2    16    26
10     2    11    21
11     2    12    22
12     2    13    23
13     3    17    27
14     4    18    28
15     5    19    29
16     6    20    30
like image 95
Roman Avatar answered Apr 20 '26 14:04

Roman



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!