3D array -> apply -> 3D array

匿名 (未验证) 提交于 2019-12-03 08:48:34

问题:

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.

回答1:

Here is a less than fantastic solution that requires foreknowledge of the dimensions of the function result matrix:

vapply(   1:dim(arr)[3],    function(x, y) arr[,,x] %*% y,    FUN.VALUE=arr[,,1],    y=cols.shuf.mx )  


回答2:

If you read the help page for apply, it basically agrees with your first sentence. It is set up with a particular design and you would need to construct a new function to do something differently. BTW: This gives you the same result much more simply than that aperm(aaply(...)) rigamarole:

arr[ , c(2,1,4,3)  , ] #------------------------- , , c = c1      b a           b2        b1        b4        b3   a1 0.4089769 0.2875775 0.5281055 0.9404673   a2 0.8830174 0.7883051 0.8924190 0.0455565  , , c = c2      b a           b2        b1        b4        b3   a1 0.9568333 0.5514350 0.1029247 0.6775706   a2 0.4533342 0.4566147 0.8998250 0.5726334  , , c = c3      b a           b2         b1        b4        b3   a1 0.3279207 0.24608773 0.6405068 0.8895393   a2 0.9545036 0.04205953 0.9942698 0.6928034 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!