How to apply function over each matrix element's indices How to apply function over each matrix element's indices r r

How to apply function over each matrix element's indices


I suspect you want outer:

> mat <- matrix(NA, nrow=5, ncol=3)> outer(1:nrow(mat), 1:ncol(mat) , FUN="*")     [,1] [,2] [,3][1,]    1    2    3[2,]    2    4    6[3,]    3    6    9[4,]    4    8   12[5,]    5   10   15> outer(1:nrow(mat), 1:ncol(mat) , FUN=function(r,c) log(r+c) )          [,1]     [,2]     [,3][1,] 0.6931472 1.098612 1.386294[2,] 1.0986123 1.386294 1.609438[3,] 1.3862944 1.609438 1.791759[4,] 1.6094379 1.791759 1.945910[5,] 1.7917595 1.945910 2.079442

That yields a nice compact output. but it's possible that mapply would be useful in other situations. It is helpful to think of mapply as just another way to do the same operation that others on this page are using Vectorize for. mapply is more general because of the inability Vectorize to use "primitive" functions.

data.frame(mrow=c(row(mat)),   # straightens out the arguments           mcol=c(col(mat)),            m.f.res= mapply(function(r,c) log(r+c), row(mat), col(mat)  ) )#   mrow mcol   m.f.res1     1    1 0.69314722     2    1 1.09861233     3    1 1.38629444     4    1 1.60943795     5    1 1.79175956     1    2 1.09861237     2    2 1.38629448     3    2 1.60943799     4    2 1.791759510    5    2 1.945910111    1    3 1.386294412    2    3 1.609437913    3    3 1.791759514    4    3 1.945910115    5    3 2.0794415

You probably didn't really mean to supply to the function what the row() and col() functions would have returned: This produces an array of 15 (somewhat redundant) 3 x 5 matrices:

> outer(row(mat), col(mat) , FUN=function(r,c) log(r+c) )


The simplest approach is just to use an f() that can be applied directly to the elements of the matrix. For example, using the matrix m from @adamleerich's Answer

m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)

There is no reason to use apply() in the case of the as.character() example. Instead we can operate on the elements of m as if it were a vector (it really is one) and replace in-place:

> m[] <- as.character(m)> m     [,1] [,2] [,3] [,4][1,] "1"  "3"  "5"  "7" [2,] "2"  "4"  "6"  "8"

The first part of that block is the key here. m[] forces the elements of m to be replaced by the output from as.character(), rather than overwriting m with a vector of characters.

So that is the general solution to applying a function to each element of a matrix.

If one really needs to use an f() that works on row and column indices then I'd write a f() using row() and col():

> m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)> row(m)     [,1] [,2] [,3] [,4][1,]    1    1    1    1[2,]    2    2    2    2> col(m)     [,1] [,2] [,3] [,4][1,]    1    2    3    4[2,]    1    2    3    4> row(m) * col(m) ## `*`(row(m), col(m)) to see this is just f()     [,1] [,2] [,3] [,4][1,]    1    2    3    4[2,]    2    4    6    8

or one that use outer() as other's have shown. If f() isn't vectorised, then I'd rethink my strategy as far as possible as there i) probably is a way to write a truly vectorised version, and ii) a function that isn't vectorised isn't going to scale very well.


You didn't tell us what kind of function you want to apply to each element, but I think that the only reason the examples in the other answers work is because the functions are already vectorized. If you really want to apply a function to each element, outer will not give you anything special that the function didn't already give you. You'll notice that the answers didn't even pass a matrix to outer!

How about following @Chase's comment and use apply.

For example, I have the matrix

m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)

If I want to turn it into a character matrix, element by element (just as an example) I could do this

apply(m, c(1,2), as.character)

Of course, as.character is already vectorized, but my special function my.special.function isn't. It only takes one argument, an element. There is no straighforward way to get outer to work with it. But, this works

apply(m, c(1,2), my.special.function)