rarraystidyrreshape2

Is there an alternative to reshape2::melt for multidimensional arrays in base R or tidyverse?


Suppose I have a 3-dimensional array g with dimensions [x,y,z]. reshape2::melt(g) would produce a data frame with columns giving indices of x,y,z and value where value contains the values in each entry of the prior array.

Given that reshape2 is superseded, is there a "one function" alternative to the functionality of reshape2::melt in base R or a more actively supported tidyverse package that I'm missing?

reshape2 recommends people use tidyr instead but I can't seem to find solutions to multi-dimensional arrays in tidyr. There is cubelyr but doesn't seem like that is very active these days either.

I can write a custom solution, just looking for something stable with the easy functionality of reshape2::melt for this kind of problem

library(reshape2)

g_as_array <- array(rnorm(9), dim = c(3,3,3)) # create a 3D array

g_as_data_frame <- reshape2::melt(g_as_array) # melt down to "tidy" format

head(g_as_data_frame)
#>   Var1 Var2 Var3      value
#> 1    1    1    1  1.4092362
#> 2    2    1    1 -2.1606972
#> 3    3    1    1  0.4334404
#> 4    1    2    1  0.2390544
#> 5    2    2    1 -0.9673617
#> 6    3    2    1  0.5668378

Created on 2022-08-25 by the reprex package (v2.0.1)


Solution

  • a <- array(1:27, dim = c(3,3,3))
    
    library(reshape2)
    DF1 <- melt(a)
    
    DF2 <- data.frame(
      expand.grid(lapply(dim(a), seq_len)),
      value = as.vector(a)
    )
    
    identical(DF1, DF2)
    #[1] TRUE
    

    If the array has dimension names:

    a <-array(letters[1:27], dim = c(3, 3, 3), dimnames = list(letters[1:3],
                                                               letters[4:6],
                                                               letters[7:9]))
    
    library(reshape2)
    DF1 <- melt(a)
        
    DF2 <- data.frame(
      expand.grid(dimnames(a)),
      value = as.vector(a)
    )
    
    identical(DF1, DF2)
    #[1] TRUE
    

    If not all dimensions have names, you would need to fill in the missing names first, e.g.:

    Map(\(x, y) if (is.null(x)) seq_len(y) else x , dimnames(a), dim(a))