2013-05-14 9 views
8

Sau khi thông minh lapply, tôi đã để lại danh sách ma trận 2 chiều.Cách chức năng để xếp chồng danh sách ma trận 2d vào ma trận 3d

Ví dụ:

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

Tôi muốn biến chúng thành một mảng 3 chiều:

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

Rõ ràng, nếu tôi đang sử dụng sao chép Tôi chỉ có thể bật simplify, nhưng sapply không đơn giản hóa kết quả đúng cách và stack không hoàn toàn. do.call(rbind,mylist) biến nó thành ma trận 2d thay cho mảng 3d.

Tôi có thể làm điều này với một vòng lặp, nhưng tôi đang tìm một cách gọn gàng và chức năng để xử lý nó.

Cách gần nhất tôi đã đưa ra là:

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

Nhưng tôi có cảm giác như đó là không thanh nha (vì nó disassembles và sau đó ráp các thuộc tính mảng của các vectơ, và cần rất nhiều thử nghiệm để làm cho an toàn (ví dụ rằng kích thước của mỗi phần tử đều giống nhau).

+3

có các abind gói – baptiste

+2

Tôi không đồng ý rằng 'cách gần nhất' của bạn được hay cho lắm và tôi tiếp tục không đồng ý rằng nó cần "rất nhiều" thử nghiệm. Nó rõ ràng là đúng và bạn cần 'do.call (c, test)' hoặc 'unlist (test)' và sau đó nó hoàn toàn đơn giản. –

+0

@Dwin có lẽ tôi quá khó trên mã của riêng tôi. Nhưng lợi dụng các nguyên tắc cơ bản của vectơ/ma trận luôn khiến tôi lo lắng. Tuy nhiên, điểm nhấn là nó có thể không phải là một giải pháp khủng khiếp. –

Trả lời

6

Bạn có thể sử dụng gói abind và sau đó sử dụng do.call(abind, c(test, along = 3))

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

Hoặc bạn có thể sử dụng simplify = 'array' trong một cuộc gọi đến sapply, (thay vì lapply). simplify = 'array' là không giống như simplify = TRUE, vì nó sẽ thay đổi lập luận higher trong simplify2array

ví dụ

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

Đối số đầu tiên cho 'abind' có thể là một danh sách, vì vậy bạn không cần' do.call': 'testArray <- abind (test, along = 3)' – cbeleites

+0

Đánh dấu câu trả lời này vì nó truy cập cả hai 'abind 'và', simplify = 'array''. –

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

hoặc nếu bạn không biết kích thước dự kiến ​​trước thời hạn:

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

câu trả lời trước đây của bạn hiện đã được tích hợp vào tôi (câu trả lời mới của bạn rất gọn gàng) – mnel

+1

@mnel, cảm ơn, tôi đã thực sự nhận thấy việc sử dụng 'simplify =" array "' gần đây trong tài liệu thành 'sapply' và sau đó thấy rằng nó cũng nằm trong 'Replicate'. Nhưng tôi đã đọc sai ý kiến ​​của OP về * không * bằng cách sử dụng Replicate, do đó tôi đã xóa câu trả lời đầu tiên của mình khi đọc lại. –

+1

@RicardoSaporta 'simplify =" array "' thực sự sẽ giải quyết vấn đề của tôi 9 lần trong số 10. Cảm ơn! –

2

Mảng chỉ đơn giản là vec nguyên tử tor với kích thước. Mỗi thành phần ma trận của test thực sự chỉ là một vectơ có kích thước. Do đó giải pháp đơn giản nhất mà tôi có thể nghĩ đến là để bỏ danh sách test thành một vectơ và chuyển đổi nó thành một mảng bằng cách sử dụng array và các thứ nguyên được cung cấp phù hợp.

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 

Nếu bạn không muốn hardcode kích thước, chúng ta phải thực hiện một số giả định nhưng có thể dễ dàng điền vào các chiều kích từ test, ví dụ

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

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

Giả định rằng kích thước của mỗi thành phần đều giống nhau, nhưng sau đó tôi không thấy cách bạn có thể đặt ma trận phụ vào mảng 3-d nếu điều kiện đó không giữ.

Điều này có vẻ khó hiểu, để hủy danh sách, nhưng điều này đơn giản là khai thác cách R xử lý ma trận và mảng dưới dạng vectơ có kích thước.

+0

@RicardoSaporta Sắp xếp có. Lấy làm tiếc; Tôi tìm câu trả lời bằng cách sử dụng 'mảng' và không thấy bất kỳ, và muốn cung cấp một số lời giải thích tôi đã thêm một câu trả lời. Lưu ý rằng bạn có lỗi trong đoạn đầu tiên - nó phải là 'c (dim (test [[1]]), 5)' –

+0

không có mồ hôi nào cả, và chắc chắn, câu trả lời của bạn cung cấp một lời giải thích tốt hơn tôi. Cảm ơn bạn đã nắm bắt, chỉnh sửa lỗi của tôi –

+0

Nếu một người muốn định hình lại mảng 3D để làm cho thứ nguyên đầu tiên của mảng tương ứng với độ dài của danh sách, dòng này sẽ làm điều đó: testMat <- aperm (tmp2, c (3,1,2)) –

10

Hãy thử điều này:

simplify2array(test) 
+0

Cảm ơn, nó làm việc cho tôi khi sử dụng với kết quả của 'foreach' –