KGeor
KGeor

Reputation: 107

Apply function using elements from each row of a matrix

I am struggling with the "apply" type functions in R. I have a matrix and what I want is to use the elements of each row of the matrix, use a user-defined function to make some calculations based on the input from the matrix, and create a new one that will store the results from these calculations.

I have figured out how to do this when the function returns only one output

So for example assume matrix A and a function that performs some kind of calculation.

> A=matrix(1:16,nrow=4)
> A
     [,1] [,2] [,3] [,4]
[1,]    1    5    9   13
[2,]    2    6   10   14
[3,]    3    7   11   15
[4,]    4    8   12   16

> B=apply(A,1,FUN=function(x) x[1]**2+2*x[2]+x[3]*x[4])
> B
[1] 128 156 188 224

What I need is to extend this in a case where the output is a vector of more than one elements, imagine for example that I want to calculate the value of three different polynomials instead of one as in the example and obtain again a 4x3 matrix that will contain the calculation of these three polynomials.

For the time being I am doing this with a "for" loop that reads the data row by row, executes the function and stores the results in a new matrix but it is painfully slow. An example is:

 A=matrix(1:16,nrow=4)
 A  
     [,1] [,2] [,3] [,4]
[1,]    1    5    9   13
[2,]    2    6   10   14
[3,]    3    7   11   15
[4,]    4    8   12   16
 calc=function(e1,e2,e3,e4){
   x1=e1*e2+3*e3*e4
   x2=e4+e2+5*e3**2-e4
   x3=e1*e2*e3*e4  
   return(c(x1,x2,x3)) 
 }

 results=matrix(nrow=4,ncol=3)

 for (i in 1:4){
   k=calc(A[i,1],A[i,2],A[i,3],A[i,4])
   results[i,]=k
 }

 results
     [,1] [,2] [,3]
[1,]  356  410  585
[2,]  432  506 1680
[3,]  516  612 3465
[4,]  608  728 6144

Any ideas of how I could apply similar operations to a matrix avoiding the "for" are more than welcome. (I am not constrained to the apply packages)

Upvotes: 0

Views: 650

Answers (3)

akrun
akrun

Reputation: 886938

Not sure if this helps:

 fun1 <- function(mat){
 x1 <- mat[,1]*mat[,2]+3*mat[,3]*mat[,4]
 x2 <- mat[,4]+mat[,2]+5*mat[,3]**2-mat[,4]
 x3 <- mat[,1]*mat[,2]*mat[,3]*mat[,4]
  cbind(x1,x2,x3)
  }
 fun1(A)
#      x1  x2   x3
# [1,] 356 410  585
# [2,] 432 506 1680
# [3,] 516 612 3465
# [4,] 608 728 6144

Upvotes: 2

Edwin
Edwin

Reputation: 3242

Your function doesn't work in the apply framework, because the function should have a vector as its argument, not individual values. If you specify the values within the function it will work:

calc=function(row){
  e1 = row[1]; e2 = row[2]; e3 = row[3]; e4 = row[4]
  x1=e1*e2+3*e3*e4
  x2=e4+e2+5*e3**2-e4
  x3=e1*e2*e3*e4  
  return(c(x1,x2,x3)) 
}

The apply function will return a full matrix, however it will create this matrix column wise. So the results of the first row will be stored into the first column, etc. This easily solved by taking the transpose of the result.

t(apply(A, 1, calc))

Upvotes: 3

Martin Markov
Martin Markov

Reputation: 113

apply(A,1,FUN=function(x){
    y<-rep(NA,3)
    y[1]=x[1]+1
    y[2]=x[2]+x[3]
    y[3]=x[4]/2
    return(t(y))
    }
    )

That worked for me. Obviously, edit the functions for y[1],y[2],y[3], and if you want more than 3, also edit the line y<-rep(NA,3)

Upvotes: 0

Related Questions