3
votes

I am trying to apply a function to each row or column of a matrix, but I need to pass a different argument value for each row.

I thought I was familiar with lapply, mapply etc... But probably not enough.

As a simple example :

> a<-matrix(1:100,ncol=10);
> a
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]    1   11   21   31   41   51   61   71   81    91
 [2,]    2   12   22   32   42   52   62   72   82    92
 [3,]    3   13   23   33   43   53   63   73   83    93
 [4,]    4   14   24   34   44   54   64   74   84    94
 [5,]    5   15   25   35   45   55   65   75   85    95
 [6,]    6   16   26   36   46   56   66   76   86    96
 [7,]    7   17   27   37   47   57   67   77   87    97
 [8,]    8   18   28   38   48   58   68   78   88    98
 [9,]    9   19   29   39   49   59   69   79   89    99
[10,]   10   20   30   40   50   60   70   80   90   100

Let's say I want to apply a function to each row, I would do :

apply(a, 1, myFunction);

However my function takes an argument, so :

apply(a, 1, myFunction, myArgument);

But if I want my argument to take a different value for each row, I cannot find the right way to do it. If I define a 'myArgument' with multiple values, the whole vector will obviously be passed to each call of 'myFunction'.

I think that I would need a kind of hybrid between apply and the multivariate mapply. Does it make sense ?

One 'dirty' way to achieve my goal is to split the matrix by rows (or columns), use mapply on the resulting list and merge the result back to a matrix :

do.call(rbind, Map(myFunction, split(a,row(a)), as.list(myArgument)));

I had a look at sweep, aggregate, all the *apply variations but I wouldn't find the perfect match to my need. Did I miss it ?

Thank you for your help.

3

3 Answers

1
votes

You can use sweep to do that.

a <- matrix(rnorm(100),10)
rmeans <- rowMeans(a)
a_new <- sweep(a,1,rmeans,`-`)
rowMeans(a_new)
0
votes

I don't think there are any great answers, but you can somewhat simplify your solution by using mapply, which handles the "rbind" part for you, assuming your function always returns the same sizes vector (also, Map is really just mapply):

a <- matrix(1:80,ncol=8)
myFun <- function(x, y) (x - mean(x)) * y
myArg <- 1:nrow(a)

t(mapply(myFun, split(a, row(a)), myArg))
0
votes

I know the topic is quiet old but I had the same issue and I solved it that way:

# Original matrix
a <- matrix(runif(n=100), ncol=5)
# Different value for each row
v <- runif(n=nrow(a))
# Result matrix -> Add a column with the row number
o <- cbind(1:nrow(a), a)
fun <- function(x, v) {
  idx <- 2:length(x)
  i <- x[1]
  r <- x[idx] / v[i]
  return(r)
}
o <- t(apply(o, 1, fun, v=v)

By adding a column with the row number to the left of the original matrix, the index of the needed value from the argument vector can be received from the first column of the data matrix.