2013-05-14 67 views
8

巧妙的lapply之後,我剩下一列2維矩陣。將2D矩陣列表堆棧到3D矩陣的函數式方法

例如:

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)將其變成二維矩陣而不是三維陣列。

我可以用循環做到這一點,但我正在尋找一個簡潔而實用的方式來處理它。

我想出最接近的方法是:

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

但我認爲這是個不雅的(因爲它拆開,然後重新組裝矢量的排列特性,並且需要大量的測試,使安全的(例如,每個元件的尺寸是相同的)。

+3

還有的abind包 – baptiste 2013-05-14 00:46:43

+2

我不同意,你最親密的方式「是不雅的,我不同意進一步,它需要測試的「很多」。這顯然是正確的,你確實需要'do.call(c,test)'或'unlist(test)',之後就完全簡單了。 – 2013-05-14 01:13:17

+0

@Dwin也許我對自己的代碼太難了。但利用矢量/矩陣的基本原理總是讓我感到緊張。但要指出的是,這可能不是一個可怕的解決方案。 – 2013-05-14 01:32:01

回答

6

可以使用abind包,然後使用do.call(abind, c(test, along = 3))

library(abind) 
testArray <- do.call(abind, c(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 
+1

'abind'的第一個參數可能是一個列表,所以你不需要'do.call':'testArray < - abind(test,along = 3)' – cbeleites 2013-05-14 10:31:35

+0

標記這個答案,因爲它同時擊中'abind '和',簡化='數組'。 – 2014-01-09 19:56:11

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 
+0

你以前的回答現在已經被納入我的了(你的新答案非常整潔) – mnel 2013-05-14 01:03:02

+1

@mnel,謝謝,我剛剛注意到最近在'sapply'文檔中使用'simplify =「array'',然後看到它也在'Replicate'中。但是我誤解了OP關於* not *使用Replicate的評論,因此我在重新閱讀時刪除了我的第一個答案。 – 2013-05-14 01:05:50

+1

@RicardoSaporta'simplify =「array」'實際上可以解決我的問題9次,滿分10分。謝謝! – 2013-05-14 01:34:04

2

一個數組只是一個原子vec tor與尺寸。 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如何處理矩陣和數組作爲具有維度的向量。

+0

@RicardoSaporta排序的是。抱歉;我使用'array'查找答案,但沒有看到任何答案,並且想要提供一些解釋,我添加了一個答案。注意你在第一個塊中有一個錯誤 - 它應該是'c(dim(test [[1]]),5)' – 2013-05-14 02:34:32

+0

根本沒有出汗,當然,你的回答比我的解釋提供了更多的解釋。感謝您的接觸,編輯我的錯誤 – 2013-05-14 02:37:19

+0

如果想要重塑3d數組以便使數組的第一維對應列表的長度,則此行將執行此操作:testMat < - aperm(tmp2,c (3,1,2)) – 2017-10-22 21:13:39

10

試試這個:

simplify2array(test) 
+0

謝謝,它在使用'foreach'的時候對我有效 – 2015-03-03 13:51:47