Search code examples
rtidyr

A simple pivot_longer on 3D array in R?


Given the array foo, how can I make a data.frame bar using pivot_longer? I have a 2-step solution using pivot_longer followed by separate_wider_delim but I can I accomplish this all in pivot_longer using the names_sep argument?

# what I have
foo <- array(1:24,dim = c(4,3,2))
dimnames(foo) <- list(NULL,paste0("varName",1:3),paste0("Iteration",1:2))

foo

#what I want
bar <- data.frame(value=1:24,
                  varName = rep(c("y1","y2","y3"),each=4),
                  Iteration = c(rep("z1",times=12),rep("z2",times=12)))
bar

# A 2-step solution
bar2 <- as.data.frame(foo) %>%
  pivot_longer(everything()) %>%
  separate_wider_delim(cols=name, delim=".", names=c("varName","Iteration"))

bar2

Solution

  • Added some name repair to get your "y"s and "z"s and also selected and arranged to match desired output. Note, names_sep is a regexp so must escape the dot.

    library(tidyr)
    library(stringr)
    library(dplyr)
    
    foo <- array(1:24,dim = c(4,3,2))
    dimnames(foo) <- list(NULL,paste0("varName",1:3),paste0("Iteration",1:2))
    
    foo %>% 
      as_tibble(
        .name_repair = ~ str_replace_all(., c("varName" = "y", "Iteration" = "z"))
      ) %>% 
      pivot_longer(
        everything(), 
        names_to = c("varName", "Iteration"), 
        names_sep = "\\."
      ) %>% 
      select(value, varName, Iteration) %>%
      arrange(value, varName, Iteration)
    #> # A tibble: 24 × 3
    #>    value varName Iteration
    #>    <int> <chr>   <chr>    
    #>  1     1 y1      z1       
    #>  2     2 y1      z1       
    #>  3     3 y1      z1       
    #>  4     4 y1      z1       
    #>  5     5 y2      z1       
    #>  6     6 y2      z1       
    #>  7     7 y2      z1       
    #>  8     8 y2      z1       
    #>  9     9 y3      z1       
    #> 10    10 y3      z1       
    #> # ℹ 14 more rows
    

    Created on 2024-04-09 with reprex v2.1.0