It seems apply
will not re-assemble 3D arrays when operating on just one margin. Consider:
arr <- array( runif(2*4*3), dim=c(2, 4, 3), dimnames=list(a=paste0("a", 1:2), b=paste0("b", 1:4), c=paste0("c", 1:3)) ) # , , c = c1 # # b # a b1 b2 b3 b4 # a1 0.7321399 0.8851802 0.2469866 0.9307044 # a2 0.5896138 0.6183046 0.7732842 0.6652637 # # , , c = c2 # b # a b1 b2 b3 b4 # a1 0.5894680 0.7839048 0.3854357 0.56555024 # a2 0.6158995 0.6530224 0.8401427 0.04044974 # # , , c = c3 # b # a b1 b2 b3 b4 # a1 0.3500653 0.7052743 0.42487635 0.5689287 # a2 0.4097346 0.4527939 0.07192528 0.8638655
Now, make a 4 x 4 matrix to shuffle columns around in each of arr[, , i]
, and use apply
to matrix multiply each a*b
sub-matrix in arr
to re-order their columns. The important point is that the result of each apply
iteration is a matrix
cols.shuf.mx <- matrix(c(0,1,0,0,1,0,0,0,0,0,0,1,0,0,1,0), ncol=4) apply(arr, 3, `%*%`, cols.shuf.mx) # c # c1 c2 c3 # [1,] 0.8851802 0.78390483 0.70527431 # [2,] 0.6183046 0.65302236 0.45279387 # [3,] 0.7321399 0.58946800 0.35006532 # [4,] 0.5896138 0.61589947 0.40973463 # [5,] 0.9307044 0.56555024 0.56892870 # [6,] 0.6652637 0.04044974 0.86386552 # [7,] 0.2469866 0.38543569 0.42487635 # [8,] 0.7732842 0.84014275 0.07192528
Whereas, I expected the result to be:
# , , c = c1 # # a 1 2 3 4 # a1 0.8851802 0.7321399 0.9307044 0.2469866 # a2 0.6183046 0.5896138 0.6652637 0.7732842 # # , , c = c2 # # a 1 2 3 4 # a1 0.7839048 0.5894680 0.56555024 0.3854357 # a2 0.6530224 0.6158995 0.04044974 0.8401427 # # , , c = c3 # # a 1 2 3 4 # a1 0.7052743 0.3500653 0.5689287 0.42487635 # a2 0.4527939 0.4097346 0.8638655 0.07192528
I can get the expected result with plyr::aaply
with:
aperm(aaply(arr, 3, `%*%`, cols.shuf.mx), c(2, 3, 1))
but was wondering if there is a simple base way to achieve this result (i.e. am I missing something obvious here to get the desired outcome).
I realize what occurs here is what is documented (If each call to FUN returns a vector of length n, then apply returns an array of dimension c(n, dim(X)[MARGIN]) if n > 1
), but it still seems weird to me that if a function returns an object with dimensions they are basically ignored.