2013-05-14 10 views
8

Nach einem cleveren lapply, bin ich links mit einer Liste von 2-dimensionalen Matrizen.Funktionelle Möglichkeit, Liste von 2D-Matrizen in 3D-Matrix zu stapeln

Zum Beispiel:

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]] 
... 

Ich mag würde, dass in ein 3-dimensionales Array drehen:

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

Natürlich, wenn ich, dass ich auf simplify nur drehen kann replizieren bin mit, aber sapply vereinfacht das Ergebnis nicht richtig, und stack schlägt völlig fehl. do.call(rbind,mylist) verwandelt es in eine 2D-Matrix anstelle von 3D-Array.

Ich kann dies mit einer Schleife tun, aber ich bin auf der Suche nach einer sauberen und funktionalen Art, damit umzugehen.

Der nächste Weg, ich habe kommen mit ist:

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

Aber ich fühle mich so unelegant ist (weil es zerlegt und dann wieder zusammen die Array-Attribute der Vektoren, und eine Menge Tests muss machen Safe (zB, dass die Abmessungen der einzelnen Elemente gleich sind).

+3

gibt es das Paket abind – baptiste

+2

Ich bin nicht einverstanden, dass Ihre engsten Weg "unelegant ist und ich nicht zustimmen weiter, dass es„eine Menge“der Prüfung benötigt. Es ist eindeutig korrekt und Sie brauchen entweder 'do.call (c, test)' oder 'unlist (test)' und danach ist es völlig unkompliziert. –

+0

@Dwin vielleicht bin ich zu hart auf meinen eigenen Code. Aber die Grundlagen der Vektoren/Matrizen zu nutzen macht mich immer nervös. Es wird jedoch darauf hingewiesen, dass dies keine schreckliche Lösung sein könnte. –

Antwort

6

Sie können die abind Paket verwenden und dann verwenden do.call(abind, c(test, along = 3))

library(abind) 
testArray <- do.call(abind, c(test, along = 3)) 

Oder Sie könnten simplify = 'array' in einem Anruf an sapply (anstelle von lapply) verwenden. simplify = 'array' ist nicht die gleiche wie simplify = TRUE, wie es das Argument higher in simplify2array

zB

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

Das erste Argument zu "abind" kann eine Liste sein, also brauchst du 'do.call' nicht:' testArray <- abind (test, along = 3) ' – cbeleites

+0

Dies ist die Antwort, da es sowohl auf 'abind 'und', simplify = 'array''. –

2
test2 <- unlist(test) 
dim(test2) <- c(dim(test[[1]]),5) 

ändern wird, oder wenn Sie nicht wissen, die erwartete Größe der Zeit voraus:

dim3 <- c(dim(test[[1]]), length(test2)/prod(dim(test[[1]]))) 
dim(test2) <- dim3 
+0

Ihre vorherige Antwort wurde nun in meine aufgenommen (Ihre neue Antwort ist sehr ordentlich) – mnel

+1

@mnel, danke, ich hatte eigentlich gerade die Verwendung von 'simplify =" array "' kürzlich in der Dokumentation zu 'sapply' bemerkt und dann gesehen dass es auch in 'Replicate' war. Aber ich hatte den Kommentar des OPs über * nicht * falsch gelesen, daher habe ich meine erste Antwort beim erneuten Lesen gelöscht. –

+1

@RicardoSaporta 'simplify =" array "' würde eigentlich mein Problem 9 mal von 10 lösen. Danke! –

2

Ein Array ist einfach ein Atom Vec tor mit Abmessungen. Jede der Matrixkomponenten von test ist wirklich nur ein Vektor mit Dimensionen. Daher ist die einfachste Lösung, die ich mir vorstellen kann, das Auflisten der Liste test in einen Vektor und das Konvertieren in ein Array unter Verwendung von array und geeignet gelieferten Abmessungen.

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 

Wenn Sie nicht die Dimensionen codieren wollen, müssen wir einige Annahmen getroffen werden, sondern kann in der Dimension von test leicht füllen, z.B.

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

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

Dies setzt voraus, dass die Abmessungen der einzelnen Komponenten sind alle gleich, aber dann sehe ich nicht, wie Sie Untermatrizen in ein 3-D-Array setzen könnten, wenn diese Bedingung nicht gilt.

Dies mag hacky scheinen, die Liste aufzurollen, aber das ist einfach ausnutzen wie R Matrizen und Arrays als Vektoren mit Dimensionen behandelt.

+0

@RicardoSaporta Art von ja. Es tut uns leid; Ich suchte nach Antworten mit 'array' und sah keine, und um eine Erklärung zu geben, fügte ich eine Antwort hinzu. Beachten Sie, dass Sie einen Fehler im ersten Chunk haben - es sollte 'c (dim (test [[1]])), 0) –

+0

kein Schwitzen sein, und sicherlich bietet Ihre Antwort ein gutes Stück mehr Erklärung als meine. Danke für den Haken, editierte meinen Fehler –

+0

Wenn man das 3D-Array umformen möchte, um die erste Dimension des Arrays entsprechend der Länge der Liste zu machen, würde diese Zeile es tun: testMat <- aperm (tmp2, c (3,1,2)) –

10

Try this:

simplify2array(test) 
+0

Danke, es funktionierte für mich, wenn ich mit dem Ergebnis von 'foreach' benutze –

Verwandte Themen