【问题标题】:converting nested list with partially empty values to R data.frame将具有部分空值的嵌套列表转换为 R data.frame
【发布时间】:2019-07-24 09:05:23
【问题描述】:

对于单个 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 的列表导致了这个问题?

我尝试了this post 中描述的一些策略,但每次尝试都有其独特的错误。

data.table "rbindlist" 方法和dplyr "bind_rows" 方法都报告了:

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

感谢您提供有关如何处理这种情况的任何提示。

【问题讨论】:

  • this
  • 我看到Error: Argument 1 must have names。有什么方法可以指定我要绑定的是子列表,而不是列表列表?

标签: r


【解决方案1】:

考虑两个 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) 

【讨论】:

    【解决方案2】:

    首先,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
    • 可能还包含列表、数据框或NULLs 的列表

    在这种情况下,递归可能会有所帮助。考虑以下代码:

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

    【讨论】:

      猜你喜欢
      • 2016-06-17
      • 2015-02-03
      • 1970-01-01
      • 2016-03-22
      • 1970-01-01
      • 2013-04-23
      • 2015-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多