【问题标题】:R - How to rbind two lists while alternating their list elementsR - 如何在交替列表元素的同时绑定两个列表
【发布时间】:2017-09-06 00:59:54
【问题描述】:

我想知道如何将两个包含向量的列表绑定到一个数据框中。例如

a<-list(c(1,2,3,4,5), c(2,3,4,5,6))
b<-list(c(3,4,5,6,7), c(4,5,6,7,8))

如何从两个列表中创建一个数据框,如下所示:

1 2 3 4 5
3 4 5 6 7
2 3 4 5 6 
4 5 6 7 8

所以我需要获取每个列表的第一个元素,然后对它们进行 rbind。然后取每个列表的第二个元素,然后 rbind 到前一个数据帧。我知道我可以使用 for 循环,但有没有更好更快的方法来做到这一点?

【问题讨论】:

  • 请将答案标记为已解决,以便社区知道并且将来寻找相同答案的人们可以更快地找到答案。我认为@thelatemail 的回答可能是最灵活/最有效的。

标签: r


【解决方案1】:

@DiscoSuperfly 答案的变体,适用于长度不均匀的对象,例如:

a <- list(c(1,2,3,4,5), c(2,3,4,5,6), c(1,1,1,1,1))
b <- list(c(3,4,5,6,7), c(4,5,6,7,8))

答案:

L <- list(a,b)
L <- lapply(L, `length<-`, max(lengths(L)))
do.call(rbind, do.call(Map, c(rbind, L)))

#     [,1] [,2] [,3] [,4] [,5]
#[1,]    1    2    3    4    5
#[2,]    3    4    5    6    7
#[3,]    2    3    4    5    6
#[4,]    4    5    6    7    8
#[5,]    1    1    1    1    1

【讨论】:

    【解决方案2】:

    使用purrr 包的解决方案。

    library(purrr)
    map2_dfr(a, b, ~data.frame(rbind(.x, .y)))
    
      X1 X2 X3 X4 X5
    1  1  2  3  4  5
    2  3  4  5  6  7
    3  2  3  4  5  6
    4  4  5  6  7  8
    

    【讨论】:

    • 基础 R 翻译 - data.frame(do.call(rbind, Map(rbind, a, b)))
    • @thelatemail 感谢分享基础 R 翻译
    【解决方案3】:
     Reduce(rbind,Map(rbind,a,b))
          [,1] [,2] [,3] [,4] [,5]
     [1,]    1    2    3    4    5
     [2,]    3    4    5    6    7
     [3,]    2    3    4    5    6
     [4,]    4    5    6    7    8
    

    【讨论】:

      【解决方案4】:

      在给出的答案中,这似乎是使用两个列表时最快的,这在很大程度上要归功于@thelatemail 的建议编辑(谢谢!)。

      试试这个:

      rbab<-do.call(rbind,c(a,b)); rbind(rbab[c(TRUE,FALSE),],rbab[c(FALSE,TRUE),])
      

      输出:

           [,1] [,2] [,3] [,4] [,5]
      [1,]    1    2    3    4    5
      [2,]    3    4    5    6    7
      [3,]    2    3    4    5    6
      [4,]    4    5    6    7    8
      

      使用上面的 c(TRUE,FALSE) 将每隔一行 a 和 b 绑定;然后我们将其翻转为 c(FALSE,TRUE) 以获取其余部分。最后,我们将它们重新绑定在一起。

      编辑:速度测试

      这是一个更大规模的速度测试,用于客观比较,它使用两个列表,每个列表包含 6000 个元素,而不是提供的原始 a 和 b。总共使用了 100 次迭代来估计这些统计数据。

      #Sample used:
      a<-list(c(1,2,3,4,5),c(2,3,4,5,6))
      b<-list(c(3,4,5,6,7),c(4,5,6,7,8))
      a<-a[rep(1:2,3e3)]
      b<-a[rep(1:2,3e3)]
      
      #Here is the collaboration version (with @thelatemail): 
      func1 <- function(){
        rbab<-do.call(rbind,c(a,b)); rbind(rbab[c(TRUE,FALSE),],rbab[c(FALSE,TRUE),])
      }
      
      #Here is my original version: 
      func2 <- function(){
        rbind(do.call(rbind,c(a,b))[c(TRUE,FALSE),],do.call(rbind,c(a,b))[c(FALSE,TRUE),])
      }
      
      #Here's a base-R translation of @ycw's answer (*translated by thelatemail)
      func3 <- function(){
        do.call(rbind, Map(rbind, a, b))
      }
      
      #Here is @Onyambu's answer (also a great answer for its brevity!): 
      func4 <- function(){
        Reduce(rbind,Map(rbind,a,b))
      }
      
      microbenchmark::microbenchmark(
        func1(),func2(),func3(),func4()
      )
      
      Unit: microseconds
          expr       min        lq      mean    median        uq       max neval
       func1()      4.39      6.46     14.74     15.85     20.24     31.94   100   
       func2()   5789.26   6578.83   7114.21   7027.57   7531.52   9411.05   100   
       func3()  10279.50  10970.70  11611.90  11245.47  11866.70  16315.00   100   
       func4() 251098.18 265936.30 273667.45 275778.04 281740.77 291279.20   100   
      

      【讨论】:

      • 非常感谢。这与上面发布的 Reduce 方法相比如何?
      • @Josh - 速度测试表明这个答案是最快的。
      • @Onyambu - OP 问题的标题是“rbind two lists in R element by element”。除此之外,我不确定所有这些答案在没有测试的情况下如何扩展,这是真的。但是,作为一般规则,只要您可以在代码中使用二进制(即 TRUE、FALSE),它就会大大加快速度。
      • 感谢基准测试,但您的函数 3 似乎是唯一将矩阵转换为数据框的函数。如果从函数 3 中删除 data.frame,函数 3 会变得最快。
      • 您在func1func2 中的结果与其他结果不同。 identical(func2(), func3())FALSEidentical(func2(), func4()) 也是 FALSE
      【解决方案5】:

      我创建了一个包含 a 和 b 的新列表,然后将其设为矩阵。我确信有一种更优雅的方法可以做到这一点。

      a <- list(c(1,2,3,4,5), c(2,3,4,5,6), c(1,1,1,1,1))
      b <- list(c(3,4,5,6,7), c(4,5,6,7,8))
      
      # empty list
      ab <- vector("list", length = length(a) + length(b)) 
      # put a and b in correct locations 
      ab[seq(1, length(ab), 2)] <- a
      ab[seq(2, length(ab), 2)] <- b
      # make the matrix
      res <- t(matrix(unlist(ab), nrow=5, ncol=length(a) + length(b)))
      

      【讨论】:

        【解决方案6】:
        > ab <-rbind(unlist(a), unlist(b))
        > ab <- rbind(ab[,1:5], ab[,6:10])
        > ab
             [,1] [,2] [,3] [,4] [,5]
        [1,]    1    2    3    4    5
        [2,]    3    4    5    6    7
        [3,]    2    3    4    5    6
        [4,]    4    5    6    7    8
        

        【讨论】:

        • 感谢您的回答。但是如果两个列表包含很多向量,有没有更通用的方法来做到这一点?
        • @Josh do.call(rbind, c(a,b))
        • 谢谢弗兰克。但是您的解决方案会产生与我想要的不同的东西。您的将 rbind 第一个列表中的所有向量,然后 rbind 第二个列表中的所有向量。
        【解决方案7】:

        我愿意:

        d <- t(as.data.frame(c(a,b))) rbind( d[ seq(1,nrow(d),by=2) ,] , d[ seq(2,nrow(d),by=2) ,])

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-01-18
          • 1970-01-01
          • 2017-02-27
          • 2019-12-24
          • 1970-01-01
          • 2021-11-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多