Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

tidyr equivalent of reshape2::melt() for deeply nested lists of vectors

Tags:

r

tidyr

reshape2

Using reshape2, it's easy to convert a deeply nested list of vectors to a long data.frame which includes information on each value's original list position.

# generate nested list of depth 3 with 2 branches at each level
n_l <- purrr::array_tree(
  array(1:2^3, rep_len(2, 3))
)

m_n_l <- reshape2::melt(n_l)

# this provides a df of values where original list position is labelled using 
# [n_dimensions] columns each with [n_branches] values. yay! that's what I want
m_n_l

#    value L3 L2 L1
# 1      1  1  1  1
# 2      5  2  1  1
# 3      3  1  2  1
# 4      7  2  2  1
# 5      2  1  1  2
#        ...

# [reshape2::melt() also handles the case where leaf node vectors have 
# arbitrary number of elements]
reshape2::melt(rapply(n_l, function(x) x * 1:sample(1:3, 1)))

reshape2 is now retired, and its users are being encouraged to use tidyr. However, I can't find a tidyr way to replicate the above functionality of reshape2::melt(). pivot_longer(), hoist(), and unnest() seem like the functions replacing melt(), but they seem to be specialised to the particular cases of data.frames or lists of data.frames.

Can tidyr do this?

like image 712
Krister Janmore Avatar asked Sep 17 '25 12:09

Krister Janmore


1 Answers

One option using rrapply could be:

Reduce(rbind, rrapply(n_l, f = function(x, .xpos) c(.xpos, x), how = "flatten"))

     [,1] [,2] [,3] [,4]
init    1    1    1    1
        1    1    2    5
        1    2    1    3
        1    2    2    7
        2    1    1    2
        2    1    2    6
        2    2    1    4
        2    2    2    8

But if you are looking for a specific tidyverse option, then one not very compact one could be:

enframe(n_l) %>%
 mutate(value = map(value, ~ enframe(., name = "name2"))) %>%
 unnest(value) %>%
 mutate(value = map(value, ~ enframe(., name = "name3"))) %>%
 unnest(value) %>%
 mutate(value = unlist(value))

   name name2 name3 value
  <int> <int> <int> <int>
1     1     1     1     1
2     1     1     2     5
3     1     2     1     3
4     1     2     2     7
5     2     1     1     2
6     2     1     2     6
7     2     2     1     4
8     2     2     2     8
like image 91
tmfmnk Avatar answered Sep 20 '25 02:09

tmfmnk