Transformer une liste de listes en dataframe

Aug 30 2020

J'ai une liste contenant un certain nombre d'autres listes, chacune contenant des nombres variables de vecteurs de caractères, avec des nombres variables d'éléments. Je veux créer un dataframe où chaque liste serait représentée sous forme de ligne et chaque vecteur de caractère dans cette liste serait une colonne. Là où le vecteur de caractères a> 1 élément, les éléments seraient concaténés et séparés en utilisant un signe "+", de sorte qu'ils puissent être stockés comme une chaîne. Les données ressemblent à ceci:

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

La sortie attendue est comme ceci:

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"))

Il n'y a pas de limite au nombre de vecteurs de caractères pouvant être contenus dans une liste, la solution doit donc créer dynamiquement des colonnes, conduisant à un df où le nombre de colonnes est égal à la longueur de la liste contenant le plus grand nombre de caractères vecteurs.

Réponses

2 RonakShah Aug 31 2020 at 03:01

Pour chaque liste dans, fruitsvous pouvez créer un dataframe d'une ligne et lier les données.

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

C'est un peu brouillon mais voici un moyen

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 une autre stratégie

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

Mais en réalité, vous devez créer chaque colonne ou ligne de votre liste, puis les combiner.

1 JorisC. Aug 31 2020 at 07:14

Une autre approche qui fusionne la liste en un data.frame en utilisant rrapply::rrapply, puis la convertit au format requis en utilisant 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