Преобразование вложенного (трехуровневого) списка во фрейм данных длинного / высокого формата - PullRequest
0 голосов
/ 17 февраля 2019

У меня есть вложенный список с 3 уровнями:

m = list(try1 = list(list(court = c("jack", "queen", "king"),
                          suit = list(diamonds = 2, clubs = 5)), 
                     list(court = c("jack", "queen", "king"),
                          suit = list(diamonds = 45, clubs = 67))), 
         try2 = list(list(court = c("jack", "queen", "king"),
                          suit = list(diamonds = 400, clubs = 300)), 
                     list(court = c("jack", "queen", "king"),
                          suit = list(diamonds = 5000, clubs = 6000))))

> str(m)
List of 2
 $ try1:List of 2
  ..$ :List of 2
  .. ..$ court: chr [1:3] "jack" "queen" "king"
  .. ..$ suit :List of 2
  .. .. ..$ diamonds: num 2
  .. .. ..$ clubs   : num 5
  ..$ :List of 2
  .. ..$ court: chr [1:3] "jack" "queen" "king"
  .. ..$ suit :List of 2
  .. .. ..$ diamonds: num 45
  .. .. ..$ clubs   : num 67
 $ try2:List of 2
  ..$ :List of 2
  .. ..$ court: chr [1:3] "jack" "queen" "king"
  .. ..$ suit :List of 2
  .. .. ..$ diamonds: num 400
  .. .. ..$ clubs   : num 300
  ..$ :List of 2
  .. ..$ court: chr [1:3] "jack" "queen" "king"
  .. ..$ suit :List of 2
  .. .. ..$ diamonds: num 5000
  .. .. ..$ clubs   : num 6000

Для каждого подсписка в try1 и try2 мне нужно извлечь подсписок suit и связать его элементы так, чтобы получилсяфрейм данных представлен в длинном формате с 4 столбцами - value (значение масти), suit (который определяет, из какого набора исходит значение, например, алмазы или булавы), iter (чтобы определить, какой подсписокиск принадлежит, то есть 1 или 2) и try (try1 или try2).

Я мог бы добиться этого, используя комбинацию expand.grid() и mapply():

grd = expand.grid(try = names(m), iter = 1:2, suit = c("diamonds", "clubs"))

grd$value = mapply(function(x, y, z) m[[x]][[y]]$suit[[z]], grd[[1]], grd[[2]], grd[[3]])

Результат:

> grd
   try iter     suit value
1 try1    1 diamonds     2
2 try2    1 diamonds   400
3 try1    2 diamonds    45
4 try2    2 diamonds  5000
5 try1    1    clubs     5
6 try2    1    clubs   300
7 try1    2    clubs    67
8 try2    2    clubs  6000

Однако мне было интересно, есть ли более общий / краткий способ воспроизведения вышеуказанного результата (предпочтительно в базе R)? Я думал об извлеченииВыделить элемент из каждого подсписка и затем рекурсивно использовать что-то вроде stack() в результирующем списке:

rapply(m, function(x) setNames(stack(x), names(x)))

Но это выдает ошибку, я не совсем уверен, почему, и я не знаю, что использоватьна своем месте.

1 Ответ

0 голосов
/ 17 февраля 2019

Мы могли бы использовать комбинацию map с melt

library(purrr)
library(reshape2)
library(dplyr)
map_df(m, ~ .x %>%
                 map(pluck, "suit")  %>% 
                   melt, .id = 'try') 

или с enframe и map

library(tibble)
map_df(m, ~ .x %>% 
              map_df(pluck, "suit") %>% 
                    map_df(~ enframe(.x, name = "iter") %>%
                       unnest, .id = "suit"), .id = 'try'  )
# A tibble: 8 x 4
#  try   suit      iter value
#  <chr> <chr>    <int> <dbl>
#1 try1  diamonds     1     2
#2 try1  diamonds     2    45
#3 try1  clubs        1     5
#4 try1  clubs        2    67
#5 try2  diamonds     1   400
#6 try2  diamonds     2  5000
#7 try2  clubs        1   300
#8 try2  clubs        2  6000
...