Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tidy method to split multiple columns using tidyr::separate

Tags:

r

purrr

tidyr

I have a data frame like so:

df <- structure(list(A = c("3 of 5", "1 of 2", "1 of 3", "1 of 3", 
"3 of 4", "2 of 7"), B = c("2 of 2", "2 of 4", "0 of 1", "0 of 0", 
"0 of 0", "0 of 0"), C = c("10 of 21", "3 of 14", "11 of 34", 
"10 of 35", "16 of 53", "17 of 62"), D = c("0 of 0", "0 of 0", 
"0 of 0", "0 of 0", "0 of 0", "0 of 0"), E = c("8 of 16", "3 of 15", 
"10 of 32", "6 of 28", "13 of 49", "9 of 48")), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -6L))

df

|A      |B      |C        |D      |E        |
|:------|:------|:--------|:------|:--------|
|3 of 5 |2 of 2 |10 of 21 |0 of 0 |8 of 16  |
|1 of 2 |2 of 4 |3 of 14  |0 of 0 |3 of 15  |
|1 of 3 |0 of 1 |11 of 34 |0 of 0 |10 of 32 |
|1 of 3 |0 of 0 |10 of 35 |0 of 0 |6 of 28  |
|3 of 4 |0 of 0 |16 of 53 |0 of 0 |13 of 49 |
|2 of 7 |0 of 0 |17 of 62 |0 of 0 |9 of 48  |

I want to split each column into 2, leaving me with something like this:

|A_attempted |A_landed |B_attempted |B_landed |C_attempted |C_landed |D_attempted |D_landed |E_attempted |E_landed |
|:-----------|:--------|:-----------|:--------|:-----------|:--------|:-----------|:--------|:-----------|:--------|
|3           |5        |2           |2        |10          |21       |0           |0        |8           |16       |
|1           |2        |2           |4        |3           |14       |0           |0        |3           |15       |
|1           |3        |0           |1        |11          |34       |0           |0        |10          |32       |
|1           |3        |0           |0        |10          |35       |0           |0        |6           |28       |
|3           |4        |0           |0        |16          |53       |0           |0        |13          |49       |
|2           |7        |0           |0        |17          |62       |0           |0        |9           |48       |

The method I am using so far is this:

df %>% 
  separate(A, sep = " of ", remove = T, into = c("A_attempted", "A_landed")) %>% 
  separate(B, sep = " of ", remove = T, into = c("B_attempted", "B_landed")) %>% 
  separate(C, sep = " of ", remove = T, into = c("C_attempted", "C_landed")) %>%  
  separate(D, sep = " of ", remove = T, into = c("D_attempted", "D_landed")) %>%  
  separate(E, sep = " of ", remove = T, into = c("E_attempted", "E_landed"))

Which is not great considering I have 15 variables. I would prefer a solution using map

There is an answer here: Apply tidyr::separate over multiple columns but that uses deprecated functions

like image 482
Shinobi_Atobe Avatar asked Sep 01 '26 08:09

Shinobi_Atobe


1 Answers

Could try:

library(tidyverse)

names(df) %>%
  map(
    function(x) 
      df %>% 
      select(x) %>% 
      separate(x, 
               into = paste0(x, c("_attempted", "_landed")), 
               sep = " of ")
    ) %>%
  bind_cols()

Output:

# A tibble: 6 x 10
  A_attempted A_landed B_attempted B_landed C_attempted C_landed D_attempted D_landed E_attempted E_landed
  <chr>       <chr>    <chr>       <chr>    <chr>       <chr>    <chr>       <chr>    <chr>       <chr>   
1 3           5        2           2        10          21       0           0        8           16      
2 1           2        2           4        3           14       0           0        3           15      
3 1           3        0           1        11          34       0           0        10          32      
4 1           3        0           0        10          35       0           0        6           28      
5 3           4        0           0        16          53       0           0        13          49      
6 2           7        0           0        17          62       0           0        9           48      

As OP suggests we can indeed avoid the last step with map_dfc:

names(df) %>% 
  map_dfc(~ df %>% 
             select(.x) %>% 
             separate(.x, 
                      into = paste0(.x, c("_attempted", "_landed")), 
                      sep = " of ")
           )
like image 109
arg0naut91 Avatar answered Sep 02 '26 22:09

arg0naut91



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!