преобразование вложенного списка с частично пустыми значениями в R data.frame - PullRequest
0 голосов
/ 02 марта 2019

Для одного списка объектов data.frames у меня обычно не возникнет проблем с преобразованием этого:

my_df <- do.call("rbind", lapply(my_list, data.frame))

Однако объект списка, который у меня есть на данный момент, является вложенным.Это список списков data.frames.Несколько замечаний:

  1. Элементы некоторых дочерних списков в родительском списке пусты.
  2. Среди дочерних списков с информацией, некоторые списки имеют более одного объекта data.frame.
  3. Количество объектов data.frame может варьироваться в разных дочерних списках.

Вот упрощенный пример того, с чем я имею дело:

List of 3
 $ 1 :List of 2
  ..$ : NULL
  ..$ : NULL
 $ 2 :List of 2
  ..$ :'data.frame':    3 obs. of  2 variables:
  .. ..$ name                   : chr [1:3] "jack" "jim" "joe" "jon"
  .. ..$ value                  : chr [1:3] "10" "12" "13" "14"
  ..$ :'data.frame':    4 obs. of  2 variables:
  .. ..$ name                   : chr [1:4] "jacky" "jane" "juanita" "julia"
  .. ..$ value                  : chr [1:4] "11" "9" "10" "14"
 $ 3 :List of 1
  ..$ :'data.frame':    5 obs. of  2 variables:
  .. ..$ name                   : chr [1:5] "adam" "ashley" "arnold" "avery" "arthur"
  .. ..$ value                  : chr [1:5] "6" "7" "11" "12" "11"

Приведенный выше подход do.call сообщает об ошибке arguments imply differing number of rows, поэтому кажется, что мои списки с data.frames с разными номерами строк вызывают проблему?

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

Подход data.table "rbindlist" и dplyr "bind_rows" оба метода сообщили:

fill=TRUE, but names of input list at position 1 is NULL

Спасибо за любые советыо том, как справиться с ситуацией.

Ответы [ 2 ]

0 голосов
/ 02 марта 2019

Во-первых, значения NULL не имеют значения, потому что rbind(NULL, NULL, ..., A, B, C, ...) точно так же, как rbind(A, B, C, ...).

Во-вторых, структура вашего списка имеет значение.Если ваш вложенный список так же прост, как ваш пример, то ответ также прост.Приведенный ниже код может решить эту проблему:

# This list is the same as your example
test <- list(
  list(NULL, NULL),
  list(data.frame(name = c("jack", "jim", "joe", "jon"), 
                  value = c("10", "12", "13", "14")),
       data.frame(name = c("jacky", "jane", "juanita", "julia"), 
                  value = c("11", "9", "10", "14"))),

  list(data.frame(name = c("adam", "ashley", "arnold", "avery", "arthur"),
                  value = c("6", "7", "11", "12", "11")))
)

# This function rbinds the dataframes inside a list
ls_rbind <- function(ls_of_df) do.call(rbind, ls_of_df)
# Applying "ls_rbind" to each of your child lists creates a list, each of whose elements is either a NULL or a dataframe
# Applying "ls_rbind" again to the result list gives you a dataframe you want
result_df <- ls_rbind(lapply(test, ls_rbind))

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

  • Элемент, не являющийся списком, т. Е. Кадр данных, или NULL
  • Список, который также может содержать списки,фреймы данных или NULL s

В этом случае рекурсии могут быть полезны.Рассмотрим следующий код:

# These two lines complicate the list structure 
test[[4]] <- test
test[[1]][[3]] <- test

recr_ls_rbind <- function(ls_of_ls) {
  are_lists <- lapply(ls_of_ls, class) == "list"
  # Any child lists will be recursively evaluated. "part1" is always a list
  part1 <- lapply(ls_of_ls[are_lists], recr_ls_rbind)
  # Applying the above function "ls_rbind" to all non-list child items and then coerce the result into a list. 
  part2 <- list(ls_rbind(ls_of_ls[!are_lists]))
  # Put part1 and part2 into the same list and apply "ls_rbind" to it.
  ls_rbind(c(part1, part2))
}
result_df <- recr_ls_rbind(test)
0 голосов
/ 02 марта 2019

Рассмотрим два do.call прогона с Filter между:

# APPEND ALL ITEMS TO SINGLE, FLAT LIST
df_list <- do.call("c", my_list)
# FILTER OUT NULL ITEMS
df_list <- Filter(NROW, df_list)

# CONCATENATE ALL DFs TO SINGLE DF
final_df <- do.call("rbind", df_list) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...