使用dplyr,purrr将列表列表中的每个第i个元素组合在一起

时间:2017-09-30 15:12:46

标签: r dplyr purrr

我有一个结构相同的列表清单如下:

    test1 <- list(first = data.frame(col1 = c(1,2), col2 = c(3,4)), 
                  second = data.frame(COL1 = c(100,200), COL2 = c(300, 400)))

    test2 <- list(first = data.frame(col1 = c(5,6), col2 = c(7,8)), 
                  second = data.frame(COL1 = c(500,600), COL2 = c(700,800)))

    orig.list <- list(test1, test2)

我想:

  1. 将每个嵌套列表的第一个元素绑定在一起,将每个嵌套列表的第二个元素绑定在一起,等等。
  2. 将结果元素重新组合到一个列表中,该列表与第一个列表具有相同的结构。
  3. 我可以通过以下方式轻松地按元素执行此元素:

        firsts <- orig.list %>% purr::map(1) %>% dplyr::bind_rows()
        seconds <- orig.list %>% purr::map(2) %>% dplyr::bind_rows()
    
        new.list <- list(first = firsts, second = seconds)
    

    但是,对于n个列表元素,这需要I:

    1. 知道每个列表中的元素数量,
    2. 知道元素的名称和顺序,以便我可以使用正确的名称和顺序重新创建新列表,
    3. 一遍又一遍地复制并通过相同的代码行。
    4. 我正在寻找如何更普遍地应用purrr:map(或其他一些tidyverse函数)来组合列表列表的所有元素,保留元素名称和顺序。

2 个答案:

答案 0 :(得分:1)

在您显示数据的最简单情况下,您可以使用pmap并行浏览列表,bind_rows组合各个数据框:

library(tidyverse)
pmap(orig.list, bind_rows)

#$first
#  col1 col2
#1    1    3
#2    2    4
#3    5    7
#4    6    8

#$second
#  COL1 COL2
#1  100  300
#2  200  400
#3  500  700
#4  600  800

identical(pmap(orig.list, bind_rows), new.list)
# [1] TRUE

为了使这一点更通用,即处理每个子列表中元素数量和名称顺序可能不同的情况,您可以使用:

map(map_df(orig.list, ~ as.data.frame(map(.x, ~ unname(nest(.))))), bind_rows)

即。将每个子列表嵌套为数据框,让bind_rows为您检查名称。

测试用例

如果test1相同,请切换test2中元素的顺序:

test2 <- list(second = data.frame(COL1 = c(500,600), COL2 = c(700,800)),
              first = data.frame(col1 = c(5,6), col2 = c(7,8)))

orig.list1 <- list(test1, test2)

map(map_df(orig.list1, ~ as.data.frame(map(.x, ~ unname(nest(.))))), bind_rows)

给出:

#$first
#  col1 col2
#1    1    3
#2    2    4
#3    5    7
#4    6    8

#$second
#  COL1 COL2
#1  100  300
#2  200  400
#3  500  700
#4  600  800

现在从 test2 中删除一个元素:

test2 <- list(first = data.frame(col1 = c(5,6), col2 = c(7,8)))
orig.list2 <- list(test1, test2)

map(map_df(orig.list2, ~ as.data.frame(map(.x, ~ unname(nest(.))))), bind_rows)

给出:

#$first
#  col1 col2
#1    1    3
#2    2    4
#3    5    7
#4    6    8

#$second
#  COL1 COL2
#1  100  300
#2  200  400

答案 1 :(得分:1)

您想要purrr::transpose

library(purrr)
library(dplyr)
transpose(orig.list) %>% map(bind_rows)

# $first
# col1 col2
# 1    1    3
# 2    2    4
# 3    5    7
# 4    6    8
# 
# $second
# COL1 COL2
# 1  100  300
# 2  200  400
# 3  500  700
# 4  600  800