包含以下列表:
> lll = list(list(5,3,4), list(5,3,7), list(6,2,1), list(6,1,3), list(5,2,1))
我期望输出用rbind转置,用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的转置输出?
您编写它的方式是,rbind
分别应用于每个子列表,因此它实际上并没有将它们与任何东西组合在一起。在这种情况下,它所做的只是向子列表添加维度属性,将其从具有length=3
的列表更改为具有dim=c(1,3)
的矩阵。cbind
做同样的事情,除了你会得到dim=c(3,1)
。关键是,正如您所写的那样,rbind
和cbind
实际上都没有用于将子列表组合在一起。这些都是由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
通常,cbind
和rbind
适用于矢量。例如:
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
,这个参数在代码中中和了rbind
和cbind
的效果。参数simplify
的?sapply
声明:
逻辑或字符串;如果可能的话,结果应该简化为向量、矩阵或高维数组吗?
实际上你的代码和下面的代码是一样的:
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
的情况)。
要得到您想要的输出,您可能想尝试使用do.call
和lapply
:
rbind
:
do.call(rbind, lapply(lll, rbind))
cbind
:
do.call(cbind, lapply(lll, cbind))
正如@zx8754所指出的,实际上可以跳过apply
的使用,只使用do.call
来完成它(我不知道的事情,对于列表中的列表)。谢谢!):
cbind
and rbind
:
do.call(cbind, lll)
do.call(rbind, lll)
谢谢!