【问题标题】:Why rbind and cbind produce same output with sapply为什么 rbind 和 cbind 与 sapply 产生相同的输出
【发布时间】:2016-09-30 14:53:38
【问题描述】:

包含以下列表:

> lll = list(list(5,3,4), list(5,3,7), list(6,2,1), list(6,1,3), list(5,2,1))

我希望输出用 rbind 和 cbind 用 sapply 转置,但它们是相同的:

> sapply(lll, rbind)
     [,1] [,2] [,3] [,4] [,5]
[1,] 5    5    6    6    5   
[2,] 3    3    2    1    2   
[3,] 4    7    1    3    1   
> sapply(lll, cbind)
     [,1] [,2] [,3] [,4] [,5]
[1,] 5    5    6    6    5   
[2,] 3    3    2    1    2   
[3,] 4    7    1    3    1   
> 
> identical(sapply(lll, cbind), sapply(lll, rbind))
[1] TRUE

为什么会这样?什么代码会产生 cbind 与 rbind 的转置输出?

【问题讨论】:

  • do.call(rbind, lapply(lll, rbind))?
  • do.call(cbind, lapply(lll, cbind))
  • 是的,这些工作。您可能想将其作为答案并进行一些解释。
  • @Abdou 为什么选择 lapply? do.call(cbind, lll); do.call(rbind, lll) ?
  • 人们可能会被欺骗认为rbindcbind 实际上组合了列表,但这只是因为sapply 在这种情况下基本上是cbind。这个例子中实际的rbindcbind 只是将子列表转换为矩阵,sapply 实际上并不关心它们是矩阵。将rbind 替换为identity,您将在此处获得相同的输出。

标签: r apply


【解决方案1】:

您编写它的方式,rbind 分别应用于您的每个子列表,因此它实际上并没有将它们与任何东西结合起来。在这种情况下,它真正所做的只是将维度属性添加到子列表,将其从带有length=3 的列表更改为带有dim=c(1,3) 的矩阵。 cbind 做同样的事情,除了你会得到dim=c(3,1)。关键是,正如您所写,rbindcbind 实际上都没有用于将子列表组合在一起。这一切都由sapply 完成,sapply 并不关心它们作为矩阵的维度。它将它们视为向量并将它们组合为列。

考虑这个更简单的例子:

> sapply(list(list(1,2,3),list(4,5,6)),rbind)
     [,1] [,2]
[1,] 1    4   
[2,] 2    5   
[3,] 3    6   

相当于这样:

> sapply(list(rbind(list(1,2,3)),rbind(list(4,5,6))),identity)

相当于这个:

> sapply(list(matrix(list(1,2,3),c(1,3)),matrix(list(4,5,6),c(1,3))),identity)

相当于这个,因为sapply关心它们的长度而不是它们的尺寸:

> sapply(list(c(1,2,3),c(4,5,6)),identity)

基本上就是这样(因为sapply 将它们组合为列):

> cbind(c(1,2,3),c(4,5,6))

您真正想要的是调用一次rbind,将每个子列表作为参数,而不是在每个子列表上单独调用它。换句话说,您希望它像这样工作:

> rbind(list(1,2,3),list(4,5,6))
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6

但是由于您已经将子列表存储在单个列表中,因此您可以使用do.call 来实现这一点,它允许您将rbind 的所有参数作为单个list 提供:

> list_of_lists <- list(list(1,2,3),list(4,5,6))
> do.call(rbind, list_of_lists)
     [,1] [,2] [,3]
[1,] 1    2    3   
[2,] 4    5    6   

【讨论】:

    【解决方案2】:

    要获得所需的输出,您可能需要尝试使用do.calllapply

    rbind:

    do.call(rbind, lapply(lll, rbind))
    

    cbind:

    do.call(cbind, lapply(lll, cbind))
    

    正如@zx8754 所指出的,实际上可以跳过apply 的使用而只使用do.call 来完成它(对于列表中的列表,我不知道这一点。谢谢!) :

    cbindrbind

    do.call(cbind, lll)
    do.call(rbind, lll)
    

    谢谢!

    【讨论】:

      【解决方案3】:

      通常,cbindrbind 适用于向量。例如,看这个:

      v <- c(3,1,2)
      cbind(v)
      #     v
      #[1,] 3
      #[2,] 1
      #[3,] 2
      
      rbind(v)
      #  [,1] [,2] [,3]
      #v    3    1    2
      

      但是sapply 有一个名为simplify 的参数,默认情况下是TRUE,并且该参数抵消了代码中rbindcbind 的影响。 ?sapply 的论点 simplify 声明:

      逻辑或字符串;如果可能,结果是否应该简化为向量、矩阵或更高维数组?

      其实你的代码做的和这段代码是一样的:

      sapply(lll, function(x) x)
      

      为了让它发挥作用,我会这样做(虽然其他人已经建议过):

      x <- do.call(rbind, lll)
      
           # [,1] [,2] [,3]
      # [1,] 5    3    4   
      # [2,] 5    3    7   
      # [3,] 6    2    1   
      # [4,] 6    1    3   
      # [5,] 5    2    1   
      
      t(x)
           # [,1] [,2] [,3] [,4] [,5]
      # [1,] 5    5    6    6    5   
      # [2,] 3    3    2    1    2   
      # [3,] 4    7    1    3    1   
      

      或者使用data.table库:

      x <- rbindlist(lll)
      t(x)
      

      或者

      x <- matrix(unlist(lll), ncol = 3, byrow = T)
      t(x)
      

      一旦我们得到一种形式的输出(例如rbind),我们就会转置结果以得到另一种形式(以完成cbind 的情况)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-02-17
        • 2021-11-16
        • 2018-06-06
        • 2012-11-14
        • 2021-08-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多