19

在聪明之后lapply,我留下了一个二维矩阵列表。

例如:

set.seed(1)
test <- replicate( 5,  matrix(runif(25),ncol=5), simplify=FALSE )
> test
[[1]]
          [,1]       [,2]      [,3]      [,4]      [,5]
[1,] 0.8357088 0.29589546 0.9994045 0.2862853 0.6973738
[2,] 0.2377494 0.14704832 0.0348748 0.7377974 0.6414624
[3,] 0.3539861 0.70399206 0.3383913 0.8340543 0.6439229
[4,] 0.8568854 0.10380669 0.9150638 0.3142708 0.9778534
[5,] 0.8537634 0.03372777 0.6172353 0.4925665 0.4147353

[[2]]
          [,1]      [,2]      [,3]      [,4]      [,5]
[1,] 0.1194048 0.9833502 0.9674695 0.6687715 0.1928159
[2,] 0.5260297 0.3883191 0.5150718 0.4189159 0.8967387
[3,] 0.2250734 0.2292448 0.1630703 0.3233450 0.3081196
[4,] 0.4864118 0.6232975 0.6219023 0.8352553 0.3633005
[5,] 0.3702148 0.1365402 0.9859542 0.1438170 0.7839465

[[3]]
...

我想把它变成一个3维数组:

set.seed(1)
replicate( 5,  matrix(runif(25),ncol=5) )    

显然,如果我使用复制,我可以打开simplify,但sapply不能正确简化结果,并且stack完全失败。 do.call(rbind,mylist)将其转换为 2d 矩阵而不是 3d 数组。

我可以用循环来做到这一点,但我正在寻找一种简洁而实用的方式来处理它。

我想出的最接近的方法是:

array( do.call( c, test ), dim=c(dim(test[[1]]),length(test)) )

但是我觉得这很不优雅(因为它会分解然后重新组装向量的数组属性,并且需要进行大量测试以确保安全(例如,每个元素的尺寸相同)。

4

4 回答 4

18

尝试这个:

simplify2array(test)
于 2013-05-14T12:31:35.313 回答
16

您可以使用该abind软件包,然后使用abind(test, along = 3)

library(abind)
testArray <- abind(test, along = 3)

或者您可以simplify = 'array'在对 , 的调用中使用sapply(而不是lapply)。simplify = 'array'不一样,simplify = TRUE因为它会改变参数highersimplify2array

例如

foo <- function(x) matrix(1:10, ncol = 5)
# the default is simplify = TRUE
sapply(1:5, foo)
      [,1] [,2] [,3] [,4] [,5]
 [1,]    1    1    1    1    1
 [2,]    2    2    2    2    2
 [3,]    3    3    3    3    3
 [4,]    4    4    4    4    4
 [5,]    5    5    5    5    5
 [6,]    6    6    6    6    6
 [7,]    7    7    7    7    7
 [8,]    8    8    8    8    8
 [9,]    9    9    9    9    9
[10,]   10   10   10   10   10
# which is *not* what you want
# so set `simplify = 'array'
sapply(1:5, foo, simplify = 'array')
, , 1

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

, , 2

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

, , 3

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

, , 4

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

, , 5

     [,1] [,2] [,3] [,4] [,5]
[1,]    1    3    5    7    9
[2,]    2    4    6    8   10
于 2013-05-14T00:47:33.277 回答
4

数组只是具有维度的原子向量。的每个矩阵分量test实际上也只是一个具有维度的向量。因此,我能想到的最简单的解决方案是将列表展开为向量,然后使用适当提供的维度test将其转换为数组。array

set.seed(1)
foo <- replicate( 5,  matrix(runif(25),ncol=5) )
tmp <- array(unlist(test), dim = c(5,5,5))

> all.equal(foo, tmp)
[1] TRUE
> is.array(tmp)
[1] TRUE
> dim(tmp)
[1] 5 5 5

如果您不想对维度进行硬编码,我们必须做出一些假设,但可以轻松地从 中填写维度test,例如

tmp2 <- array(unlist(test), dim = c(dim(test[[1]]), length(test)))

> all.equal(foo, tmp2)
[1] TRUE

这假设每个组件的尺寸都是相同的,但是如果该条件不成立,我看不出如何将子矩阵放入 3-d 数组中。

展开列表可能看起来很老套,但这只是利用 R 如何将矩阵和数组处理为具有维度的向量。

于 2013-05-14T02:12:32.067 回答
2
test2 <- unlist(test)
dim(test2) <- c(dim(test[[1]]),5)

或者如果您不提前知道预期大小:

dim3 <- c(dim(test[[1]]), length(test2)/prod(dim(test[[1]])))
dim(test2) <- dim3
于 2013-05-14T00:55:35.140 回答