1

I want to find the simplest way to apply a function across slices of an array, where each application of the function returns a matrix, and receive a sensible array object as the final answer.

I feel like there should be a simple way to do this with apply function, but I feel like I need a simplify = 'array' option, which would be super convenient. The closest I get is this:

dims = c(2,3,10,4,5)
arr = array(runif(prod(dims)),dim = dims, dimnames = 
          list(
            paste0('a',1:dims[1]),
            paste0('b',1:dims[2]),
            paste0('c',1:dims[3]),
            paste0('d',1:dims[4]),
            paste0('e',1:dims[5])
          ))

result = apply(arr, c(4,5), function(x) apply(x, c(3), function(y) (y - y[,1])^2 ) )

The result should be an array with dimension c(2,3,10,4,5) or some permutation thereof.

I could get to the right form by calling as.array on result with the appropriate dimensions, but there should be an easier way that preserves the dimnames automatically.

3
  • 2
    To do it with apply, specify the margins you want to keep: apply(arr, 2:5, function(x){mean(x^2)}) Commented Mar 31, 2017 at 2:29
  • 1
    @alistaire - that should definitely be an answer - it is super simple. apply(arr^2, 2:5, mean) would even work in this particular case. Commented Mar 31, 2017 at 3:13
  • Sorry I gave a bad example. I will correct the example to comport with the wording and the actual goal of the question... Commented Mar 31, 2017 at 16:38

2 Answers 2

1

This can be done with the aaply function in plyr package. This is one of several apply functions in this package, where the naming convention is that aa in aaply stands for array to array.

dims = c(2,3,10,4,5)
arr = array(runif(prod(dims)),dim = dims, dimnames = 
          list(
            paste0('a',1:dims[1]),
            paste0('b',1:dims[2]),
            paste0('c',1:dims[3]),
            paste0('d',1:dims[4]),
            paste0('e',1:dims[5])
          ))

aresult = (aaply(arr, c(4,5), function(x) aaply(x, c(3), function(y) (y - y[,1])^2 ) ) )
result = aperm(abind(aresult), c(4,5,3,1,2))
Sign up to request clarification or add additional context in comments.

Comments

0

To iterate over a multidimensional array with apply, specify the margins you want to keep. It's easier to visualize in two dimensions:

m <- matrix(1, 2, 3)

m
#>      [,1] [,2] [,3]
#> [1,]    1    1    1
#> [2,]    1    1    1

apply(m, 1, sum)
#> [1] 3 3

—iterating over rows keeps that dimension, and collapses the unmentioned column one. For the more complicated array in question, then,

res <- apply(arr, 2:5, function(x){mean(x^2)})
# or even just apply(arr^2, 2:5, mean) (h/t @thelatemail)

str(res)
#>  num [1:2, 1:3, 1:4, 1:5] 0.313 0.215 0.32 0.29 0.288 ...
#>  - attr(*, "dimnames")=List of 4
#>   ..$ : chr [1:2] "b1" "b2"
#>   ..$ : chr [1:3] "c1" "c2" "c3"
#>   ..$ : chr [1:4] "d1" "d2" "d3" "d4"
#>   ..$ : chr [1:5] "e1" "e2" "e3" "e4" ...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.