2

I have a simple matrix:

mat = rbind(c(1:3),c(4:6),c(7:9))  

mat
#      [,1] [,2] [,3]
# [1,]    1    2    3
# [2,]    4    5    6
# [3,]    7    8    9

I want to now reverse the matrix row-wise. That is I want to obtain:

revMat
#      [,1] [,2] [,3]
# [1,]    3    2    1
# [2,]    6    5    4
# [3,]    9    8    7

To do this I tried

 apply(mat, 1, rev)

And the result was:

#      [,1] [,2] [,3]
# [1,]    3    6    9
# [2,]    2    5    8
# [3,]    1    4    7

I find this to be extremely strange. It's like the rows are reversed and then the final matrix is transposed. I don't understand why. If I try simply, for instance,

apply(mat, 2, rev)

it gives me the expected reversal of each column

#      [,1] [,2] [,3]
# [1,]    7    8    9
# [2,]    4    5    6
# [3,]    1    2    3

Therefore to obtain the final result I have to perform

t(apply(t(bg), 2, rev))

Thus obtaining the required matrix is NOT a problem for me, but I don't understand the "anomaly" in the behavior of apply/ reverse. Can anyone explain this to me?

Edit: To make clear the distinction, I already know how to do the reversal. I want to know WHY this happens. How to is clear from many earlier questions including

How to reverse a matrix in R?

Community
  • 1
  • 1
  • Possible duplicate of [How to reverse a matrix in R?](http://stackoverflow.com/questions/9135799/how-to-reverse-a-matrix-in-r) – MichaelChirico Mar 24 '17 at 17:23
  • See `?apply`/Value: "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`." – MichaelChirico Mar 24 '17 at 17:25
  • Why not simply `mat[,ncol(mat):1]`? The "anomaly" of which you speak is that for each iteration of `apply`, it captures the result into a column regardless of the original margin. That is, if you do `apply(mat, 1, rev)`, processing it *by row*, you expect each row reversed to be captured into rows, but instead they are captured into columns. However, `apply(mat, 2, rev)` does indeed capture into columns, so that result seems less unintuitive. As much as this seems inconsistent to me, it is the way it has always been and likely shall be with R ... – r2evans Mar 24 '17 at 17:26

2 Answers2

8

apply always puts the result in the first dimension. See ?apply for more information. Assuming this input:

mat <- matrix(1:9, 3, byrow = TRUE)

here are some alternatives:

1) transpose

t(apply(mat, 1, rev))

2) avoid apply with indexing

mat[, 3:1]

3) iapply An idempotent apply was posted here: https://stat.ethz.ch/pipermail/r-help/2006-January/086064.html Using that we have:

iapply(mat, 1, rev)

There was also an idempotent apply, iapply, in version 0.8.0 of the reshape package (but not in the latest version of reshape): https://cran.r-project.org/src/contrib/Archive/reshape/

4) rollapply rollapply in the zoo package can be used:

library(zoo)

rollapply(mat, 1, rev, by.column = FALSE)

5) tapply The tapply expression here returns a list giving us the opportunity to put it together in the way we want -- in this case using rbind:

do.call("rbind", tapply(mat, row(mat), rev))

6) multiply by a reverse diagonal matrix Since rev is a linear operator it can be represented by a matrix:

mat %*% apply(diag(3), 1, rev)

or

mat %*% (row(mat) + col(mat) == 3+1)
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
  • Holy cow, idempotent `apply` is exactly what I have wanted/needed too many times to count (I'm tired of `t(apply(...))`). It looks like "improvements" to this `iapply` did not progress past this, including (a) using the `...` it captures (a simple edit), (b) doesn't deal with higher-dimensional returns well. I'm guessing you know of no further work since you are posting this; I'd love to see this brought back into the light somehow, perhaps adding it to `reshape`. – r2evans Mar 24 '17 at 17:42
  • I've been looking since I posted my comment :-). It isn't mentioned directly in commit notes, so it must be buried ... – r2evans Mar 24 '17 at 17:48
3

If you look at the help for apply(), this is exactly the behavior you would expect:

Value

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.

a nice option to do what you want is to use indexing:

mat[,ncol(mat):1]
David Heckmann
  • 2,899
  • 2
  • 20
  • 29