Search code examples
rtidyr

R: gather multiple sets of columns with tidyr pivot_longer()


I am trying to gather two sets of columns. Each set needs to end up in a new column, but the rows data is linked, so sequential uses of tidyr::gather() won't guarantee retention of cross-column organization. It looks like tidyr::pivot_longer() can accomplish this, but I am stumped. A similar post is here, but the answer involves using grep to rename columns, which I can't unravel and also shouldn't be necessary here.

library(tidyverse)

df <- data.frame(
  Position=1:5,
  A_Width=3:7,
  B_Width=4:8,
  A_Error=seq(0, 2.0, 0.5),
  B_Error=seq(0.3, 1.5, 0.3)
  )


df <- df %>%
  tidyr::pivot_longer(
    cols=c(A_Width, B_Width, A_Error, B_Error),
    names_to= ? ,
    names_pattern= ? ,
    )

##Desired Data Frame
df_long <- data.frame(
  Position=rep(1:5,2),
  Group=c(rep("A",5), rep("B",5)),
  Width=c(3:7,4:8),
  Error=c(seq(0, 2.0, 0.5), seq(0.3, 1.5, 0.3))
  )


Solution

  • We can use .value with names_to to use the second part of the column names to specify the new columns those values should go to.

    df |>
      pivot_longer(-Position, names_sep = "_", names_to = c("Group", ".value"))
    

    Result (in order as encountered, could sort)

    # A tibble: 10 × 4
       Position Group Width Error
          <int> <chr> <int> <dbl>
     1        1 A         3   0  
     2        1 B         4   0.3
     3        2 A         4   0.5
     4        2 B         5   0.6
     5        3 A         5   1  
     6        3 B         6   0.9
     7        4 A         6   1.5
     8        4 B         7   1.2
     9        5 A         7   2  
    10        5 B         8   1.5