Search code examples
rdplyrtidyrnamesunnest

R: How to keep names while unnesting doubled nested tibble?


at the moment I'm trying to figure out how to keep the names of an inner and other list nested within a tibble while unnesting.

The .id parameter of the unnest function is the closest I found, but it starts to number the values instead of using the given names.

here is a MWE with my idea of the final tibble:

library(dplyr)
library(tidyr)

df.1 <- tibble(
  x = list("Foo","Bar"),
  y = list(
    list(a = list(aa = 1, ab = 2), b = list(ba = 6, bb = 22)),
    list(c = list(ca = 561, cb = 35), d = list(da = 346, db = 17))
  )
)

df.2 <- unnest(df.1, .id = "name.outher")
df.3 <- unnest(df.2, .id = "name.inner")

# How do I get from this:
#
#-----------------------------------------------------------------------
#  x  |                              y                                 |
#-----+----------------------------------------------------------------+
# Foo | list(a = list(aa = 1, ab = 2), b = list(ba = 6, bb = 22))      |
#-----+----------------------------------------------------------------+
# Bar | list(c = list(ca = 561, cb = 35), d = list(da = 346, db = 17)) |
#-----------------------------------------------------------------------
#
# to this:
#
#---------------------------------------
#  x  | name.outher | y   | name.inner |
#-----+-------------+-----+------------+
# Foo |      a      | 1   |     aa     |
#-----+-------------+-----+------------+
# Foo |      a      | 2   |     ab     |
#-----+-------------+-----+------------+
# Foo |      b      | 6   |     ba     |
#-----+-------------+-----+------------+
# Foo |      b      | 22  |     bb     |
#-----+-------------+-----+------------+
# Bar |      c      | 561 |     ca     |
#-----+-------------+-----+------------+
# Bar |      c      | 35  |     cb     |
#-----+-------------+-----+------------+
# Bar |      d      | 346 |     da     |
#-----+-------------+-----+------------+
# Bar |      d      | 17  |     db     |
#-------------------------------------
# 
# instead of this:
#
#---------------------------------------
#  x  | name.outher | y   | name.inner |
#-----+-------------+-----+------------+
# Foo |      1      | 1   |     1      |
#-----+-------------+-----+------------+
# Foo |      1      | 2   |     1      |
#-----+-------------+-----+------------+
# Foo |      1      | 6   |     2      |
#-----+-------------+-----+------------+
# Foo |      1      | 22  |     2      |
#-----+-------------+-----+------------+
# Bar |      2      | 561 |     3      |
#-----+-------------+-----+------------+
# Bar |      2      | 35  |     3      |
#-----+-------------+-----+------------+
# Bar |      2      | 346 |     4      |
#-----+-------------+-----+------------+
# Bar |      2      | 17  |     4      |
#---------------------------------------

Do you have any idea how i can preserve the names while unnesting this data structure?


Solution

  • We can melt

    library(reshape2)
    library(dplyr)
    df.1 %>% 
       .$y %>% 
       melt %>%
       select(x = L1, name.outher = L2, y = value, name.inner = L3)
    #  x name.outher   y name.inner
    #1 1           a   1         aa
    #2 1           a   2         ab
    #3 1           b   6         ba
    #4 1           b  22         bb
    #5 2           c 561         ca
    #6 2           c  35         cb
    #7 2           d 346         da
    #8 2           d  17         db
    

    Or use map and as_tibble

    library(tidyverse)
    df.1 %>%
       pull(y) %>% 
       map_df(~ as_tibble(.x) %>%
                    map_df(~as_tibble(.x) %>%
                        gather(name.inner, y), .id = 'name.outer'),
         .id = 'x')
    # A tibble: 8 x 4
    #  x     name.outer name.inner     y
    #  <chr> <chr>      <chr>      <dbl>
    #1 1     a          aa             1
    #2 1     a          ab             2
    #3 1     b          ba             6
    #4 1     b          bb            22
    #5 2     c          ca           561
    #6 2     c          cb            35
    #7 2     d          da           346
    #8 2     d          db            17