【问题标题】:Turn a list with elements of unequal length into a two column dataframe in R (dplyr preferred)将具有不等长度元素的列表转换为 R 中的两列数据框(首选 dplyr)
【发布时间】:2021-10-21 14:23:54
【问题描述】:

我有一个包含 3 个元素的列表,每个元素都有不同的值集和数量。我想把这个列表变成一个简单的两列数据框。

一列是列表元素的值,第二列是列表元素本身的名称。

myList <- list(A = c(1,2,3),
               B = c(10,20,30,40),
               C = c(100,200,300,400,500))

所以理想的结果是这样的:

Value     List
1         A
2         A
10        B
100       C
......

所以我知道我可以使用一系列 rbind 来做到这一点:

df <-   data.frame(Value = myList[[A]],cluster = A) %>%
  rbind(data.frame(Value = myList[[B]],cluster = B)) %>%
  rbind(data.frame(Value = myList[[C]],cluster = C))

我可能可以用循环或 lapply 清理它...但似乎应该有更直接的方法来获得它!

任何帮助将不胜感激。

【问题讨论】:

    标签: r list dataframe dplyr


    【解决方案1】:

    我们可以从base R使用stack

    stack(myList)
    

    -输出

       values ind
    1       1   A
    2       2   A
    3       3   A
    4      10   B
    5      20   B
    6      30   B
    7      40   B
    8     100   C
    9     200   C
    10    300   C
    11    400   C
    12    500   C
    

    【讨论】:

    • 哦,我什至不知道这个功能!这是完美的,谢谢。
    • 当我尝试这个时,我得到一个错误:data.frame中的错误(values = unlist(unname(x)),ind,stringsAsFactors = FALSE):参数意味着不同的行数:41, 0
    • @MaxF 不知道这个问题。这是基于您的示例,对我来说效果很好
    • @MaxF 另外,请注意stack 函数也可以在其他包中找到。因此,您可能需要检查其他包中的 stack 是否屏蔽了基本 R 堆栈函数
    • 哦,这样更干净。我用for循环做到了。谢谢!!
    【解决方案2】:

    如果你想使用tidyverse(不确定是否可以使用dplyr),你可以使用

    library(magrittr)
    tibble::enframe(myList) %>% tidyr::unnest(cols = value)
    

    输出

    # A tibble: 12 x 2
       name  value
       <chr> <dbl>
     1 A         1
     2 A         2
     3 A         3
     4 B        10
     5 B        20
     6 B        30
     7 B        40
     8 C       100
     9 C       200
    10 C       300
    11 C       400
    12 C       500
    

    首先,tibble::enframe(myList) 将返回一个包含两列和三行的 tibblename 列将是原始 list 中每个元素的名称,而值本身将是 data.frames,每个列都包含具有每个列表中值的列。

    然后,tidyr::unnest(cols = value) 只是 unnests value 列。


    也就是说,我鼓励您考虑@akrun 的回答,因为utils::stack(myList) 的速度要快得多,而且不那么冗长。

    (编辑添加@Martin Gal 使用purrr 的方法)

    microbenchmark::microbenchmark(
       tidyverse = tibble::enframe(myList) %>% tidyr::unnest(cols = value),
       baseR = utils::stack(myList),
       purrr = purrr::map_df(myList, ~data.frame(value = .x), .id = "id"),
       times = 10000
    )
    
    

    输出

    Unit: microseconds
         expr      min       lq      mean    median        uq       max neval
     tidyverse 1937.067 2169.251 2600.4402 2301.1385 2592.7305 77715.238 10000
         baseR  144.218  182.112  227.6124  202.0755  230.0960  5476.169 10000
         purrr  350.265  417.803  523.7954  455.4410  520.3555 71673.820 10000
    

    【讨论】:

    • 我添加了一个答案。随时更新您的基准。 :-)
    • 好主意!!甚至没有想过purrr
    • 非常感谢您使用 tidyverse 语法解决这个问题!不过,我同意基本 R 解决方案非常好用且高效。
    【解决方案3】:

    一个使用purrr的选项:

    library(purrr)
    
    map_df(myList, ~data.frame(value = .x), .id = "id")
    

    返回

       id value
    1   A     1
    2   A     2
    3   A     3
    4   B    10
    5   B    20
    6   B    30
    7   B    40
    8   C   100
    9   C   200
    10  C   300
    11  C   400
    12  C   500
    

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 1970-01-01
      • 2013-09-30
      • 1970-01-01
      • 1970-01-01
      • 2017-10-31
      • 2018-08-07
      • 2020-02-18
      • 1970-01-01
      相关资源
      最近更新 更多