Преобразование списка списков в фрейм данных

#r

#r

Вопрос:

У меня есть список, содержащий ряд других списков, каждый из которых содержит разное количество символьных векторов с разным количеством элементов. Я хочу создать фрейм данных, в котором каждый список был бы представлен в виде строки, а каждый вектор символов в этом списке был бы столбцом. Если символьный вектор содержит > 1 элемента, элементы будут объединены и разделены с помощью знака » «, чтобы их можно было сохранить как одну строку. Данные выглядят следующим образом:

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

  

Ожидаемый результат выглядит следующим образом:

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

Нет ограничений на количество символьных векторов, которые могут содержаться в списке, поэтому решение должно динамически создавать столбцы, что приводит к df, где количество столбцов равно длине списка, содержащего наибольшее количество символьных векторов.

Ответ №1:

Для каждого списка в fruits вы можете создать фрейм данных в одну строку и связать данные.

 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:

Это немного запутанно, но вот один из способов

 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
  

или другая стратегия

 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
  

Но на самом деле вам нужно либо построить каждый столбец или строку из вашего списка, а затем объединить их вместе.

Ответ №3:

Другой подход, который преобразует список в data.frame с помощью rrapply::rrapply , а затем преобразует его в требуемый формат с помощью 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