RFen
RFen

Reputation: 161

R - Apply function with different argument value for each row/column of a matrix

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.

Upvotes: 4

Views: 4115

Answers (3)

FlorianSchunke
FlorianSchunke

Reputation: 581

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.

Upvotes: 0

BrodieG
BrodieG

Reputation: 52637

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))

Upvotes: 1

Rentrop
Rentrop

Reputation: 21497

You can use sweep to do that.

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

Upvotes: 1

Related Questions