【问题标题】:Neatest way to build a data frame from a list of lists in R从 R 中的列表列表构建数据框的最佳方法
【发布时间】:2018-07-14 11:03:22
【问题描述】:

我有一个希望转换为数据框(特别是小标题)的子列表列表;例如:

myList <- list(
        list(var1=1,var2=2,var3=3,var4=4,var5=5,var6=6),
        list(var1=4,var2=5,var3=6,var4=7,var5=8,var6=9),
        list(var1=7,var2=8,var3=9,var4=1,var5=2,var6=3)
)

使用以下代码,我可以将选定的变量提取到 tibble 数据框

myDF <- tbl_df(cbind(
  var1 = lapply(myList, '[[', "var1"),
  var2 = lapply(myList, '[[', "var2"),
  var5 = lapply(myList, '[[', "var5"),
  var6 = lapply(myList, '[[', "var6")
))  

但它非常冗长。有没有更简洁的方法(可能使用 purrr 映射函数)可以将选定的子元素从每个列表中拉出并将它们填充到一行中?

此外,如果子列表本身包含列表,如何最好地提取这些列表的元素;例如:

 myList <- list(
        list(var1=1,var2=2,var3=3,list4=list(varA="a",varB="b")),
        list(var1=4,var2=5,var3=6,list4=list(varA="c",varB="d")),
        list(var1=7,var2=8,var3=9,list4=list(varA="e",varB="f"))
)    

我怎样才能得到类似以下的工作:

myDF <- tbl_df(cbind(
  var1 = lapply(myList, '[[', "var1"),
  var2 = lapply(myList, '[[', "var2"),
  var4 = lapply(myList, '[[', "list4$varA")
)) 

我想从列表 4 中提取特定元素,但使用 $ 表示法向下钻取到下一个级别不起作用?

【问题讨论】:

    标签: r list


    【解决方案1】:

    由于数据框只是列表,如果您的列表没有嵌套多次。

    library(tidyverse)
    myList %>%
      map(as.data.frame) %>%
      bind_rows() %>%
      select(var1, var2, var5, var6)
    
    #    var1 var2 var5 var6
    # 1    1    2    5    6
    # 2    4    5    8    9
    # 3    7    8    2    3
    

    或者甚至是下面的bind_rows()实际上适用于列表列表。

    myList %>%
      bind_rows() %>%
      select(var1, var2, var5, var6)
    
    #    var1  var2  var5  var6
    #    <dbl> <dbl> <dbl> <dbl>
    # 1  1.00  2.00  5.00  6.00
    # 2  4.00  5.00  8.00  9.00
    # 3  7.00  8.00  2.00  3.00
    

    但有时可能是每个列表元素只有一些公共元素,而您只想选择那些特定的元素

    myList %>%
      map(as.data.frame) %>%
      map(~ select(.x, var1, var2, var5, var6)) %>%
      bind_rows()
    
    #    var1 var2 var5 var6
    # 1    1    2    5    6
    # 2    4    5    8    9
    # 3    7    8    2    3
    

    对于列表嵌套不止一次的情况,使用来自purrrflatten() 进行调查

    myList2 <- list(
      list(var1=1,var2=2,var3=3,list4=list(varA="a",varB="b")),
      list(var1=4,var2=5,var3=6,list4=list(varA="c",varB="d")),
      list(var1=7,var2=8,var3=9,list4=list(varA="e",varB="f"))
    )  
    
    myList2 %>%
      map(flatten) %>%
      bind_rows()
    
    #   var1  var2  var3 varA  varB 
    #   <dbl> <dbl> <dbl> <chr> <chr>
    # 1  1.00  2.00  3.00 a     b    
    # 2  4.00  5.00  6.00 c     d    
    # 3  7.00  8.00  9.00 e     f  
    

    并根据需要应用select(),名称将是各个元素的名称。要非常小心不同元素中的重复名称,因为它只需要一个。

    在某些情况下,tibble 中的 enframe() 函数也很有用。

    【讨论】:

    • 好的;我可能应该澄清一下,但我的列表确实包含一些嵌套列表(我想忽略这些列表,只选择一些特定的非嵌套变量)。因此,在这种情况下,首先自动将列表展平为数据框的解决方案将失败。我正在寻找的是介于 SQL Select 和“With Mylist”类型方法之间的某个地方(回到 20 年前我的 VBA / VB6 天),这样我就可以提取一些(但不是全部)变量而无需每次都明确引用 mylist。
    • @BrisbanePom 你确定这行不通吗.... 提供一个更好的例子,否则我已经相当广泛地涵盖了场景。
    • 嗨@zacdav - 很难重新创建作为我应用它的真实世界示例是一个更复杂的列表,它使用商业敏感数据 - 但是当我应用“扁平化方法”时,我收到以下错误: bind_rows_(x, .id) 中的错误:大小不兼容 (1 != 4)。最终我使用它从 JSON 派生的列表中提取数据,所以理想情况下我想先选择元素,然后删除那些我在转换为数据框之前,不希望避免由于列表中的嵌套级别而导致展平失败的情况。
    • 除非你重建一个例子,否则我绝对不能帮助你,我只是没有时间去尝试根据松散的描述重建一些东西。修改数据,重要的是结构。
    【解决方案2】:

    对于第一种情况,一个可能的 base-R 解决方案:

    > data.frame(do.call(rbind, myList))[c("var1", "var2", "var5", "var5")]
    var1 var2 var5 var6
    1    1    2    5    6
    2    4    5    8    9
    3    7    8    2    3
    

    【讨论】:

    • 我认为这不会完全达到我需要的结果;请注意,并非列表的所有元素都被选中。例如。 Var3 存在于列表中,但应被忽略。我所追求的类似于 Select 语句,但我不想每次都明确引用该列表。
    猜你喜欢
    • 1970-01-01
    • 2013-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-20
    • 2015-04-21
    • 2015-04-20
    • 2014-04-14
    相关资源
    最近更新 更多