Transformar uma lista de listas em dataframe

Aug 30 2020

Eu tenho uma lista contendo várias outras listas, cada uma das quais contendo vários números de vetores de caracteres, com vários números de elementos. Eu quero criar um dataframe onde cada lista seria representada como uma linha e cada vetor de caractere dentro dessa lista seria uma coluna. Onde o vetor de caracteres tem> 1 elemento, os elementos seriam concatenados e separados usando um sinal "+", para que pudessem ser armazenados como uma string. Os dados são assim:

fruits <- list(
  list(c("orange"), c("pear")),
  list(c("pear", "orange")),
  list(c("lemon", "apple"),
       c("pear"),
       c("grape"),
       c("apple"))
)

A saída esperada é assim:

fruits_df <- data.frame(col1 = c("orange", "pear + orange", "lemon + apple"),
           col2 = c("pear", NA, "pear"), 
           col3 = c(NA, NA, "grape"),
           col4 = c(NA, NA, "apple"))

Não há limite para o número de vetores de caracteres que podem estar contidos em uma lista, então a solução precisa criar colunas dinamicamente, levando a um df onde o número de colunas é igual ao comprimento da lista contendo o maior número de caracteres vetores.

Respostas

2 RonakShah Aug 31 2020 at 03:01

Para cada lista, fruitsvocê pode criar um dataframe de uma linha e vincular os dados.

dplyr::bind_rows(lapply(fruits, function(x) as.data.frame(t(sapply(x, 
                 function(y) paste0(y, collapse = "+"))))))

#           V1   V2    V3    V4
#1      orange pear  <NA>  <NA>
#2 pear+orange <NA>  <NA>  <NA>
#3 lemon+apple pear grape apple
2 MrFlick Aug 31 2020 at 02:58

Isso é um pouco confuso, mas aqui está uma maneira

cols <-  lapply(fruits, function(x) sapply(x, paste, collapse=" + "))
ncols <- max(lengths(cols))
dd <- do.call("rbind.data.frame", lapply(cols, function(x) {length(x) <- ncols; x}))
names(dd)  <- paste0("col", 1:ncol(dd))
dd

#            col1 col2  col3  col4
# 1        orange pear  <NA>  <NA>
# 2 pear + orange <NA>  <NA>  <NA>
# 3 lemon + apple pear grape apple

ou outra estratégia

ncols <- max(lengths(fruits))
dd <- data.frame(lapply(seq.int(ncols), function(x) sapply(fruits, function(y) paste(unlist(y[x]), collapse=" + "))))
names(dd)  <- paste0("col", 1:ncols)
dd

Mas realmente você precisa construir cada coluna ou linha de sua lista e então combiná-las.

1 JorisC. Aug 31 2020 at 07:14

Outra abordagem que funde a lista em um data.frame usando rrapply::rrapplye, em seguida, a converte no formato necessário usando data.table::dcast:

library(rrapply)
library(data.table)

## melt to long data.frame
long <- rrapply(fruits, f = paste, how = "melt", collapse = " + ")

## cast to wide data.table
setDT(long)
dcast(long[, .(L1, L2, value = unlist(value))], L1 ~ L2)[, !"L1"]
#>              ..1  ..2   ..3   ..4
#> 1:        orange pear  <NA>  <NA>
#> 2: pear + orange <NA>  <NA>  <NA>
#> 3: lemon + apple pear grape apple