HoneyBadger
HoneyBadger

Reputation: 108

Multiplication of columns of a data frame to their respective cell value in a matrix

I have to multiply columns of a data frame with an assigned cell value from another matrix. This would, by definition, mean that the number of columns of data frame are equal to number of elements in the matrix.

For eg,

I have a matrix like this

         [,1]       [,2]   
[1,] 0.9470883 0.90148918
[2,] 0.6953117 0.69216633

and a data frame which looks like this

  id val1 val2 val3 val4
1  1    1    1    3    5
2  2    2    1    3    5
3  3    1    1    4    5
4  4    2    1    4    5
5  5    1    1    3    6
6  6    2    1    3    6
7  7    1    1    4    6
8  8    2    1    4    6

Each cell of matrix has to be multiplied by respective column of data frame. The matrix can be read in row wise/column wise fashion. Doing this (row wise) the fields would be multiplied as

df$val1 <- df$val1*mat[1,1]  #mat[1,1] is 0.9470883
df$val2 <- df$val2*mat[1,2]  #mat[1,2] is 0.90148918
df$val3 <- df$val3*mat[2,1]  #mat[2,1] is 0.6953117
df$val4 <- df$val4*mat[2,2]  #mat[2,2] is 0.69216633

So that the output is

  id      val1      val2     val3     val4
1  1 0.9470883 0.9014892 2.085935 3.460832
2  2 1.8941766 0.9014892 2.085935 3.460832
3  3 0.9470883 0.9014892 2.781247 3.460832
4  4 1.8941766 0.9014892 2.781247 3.460832
5  5 0.9470883 0.9014892 2.085935 4.152998
6  6 1.8941766 0.9014892 2.085935 4.152998
7  7 0.9470883 0.9014892 2.781247 4.152998
8  8 1.8941766 0.9014892 2.781247 4.152998

I want to do this over bigger dimensions of matrix and data frame with something faster than for-loops.

Upvotes: 0

Views: 241

Answers (3)

akrun
akrun

Reputation: 887981

We could also use the sweep

df[-1] <- sweep(df[-1], MARGIN=2, c(t(mat)), '*')
df
#  id      val1      val2     val3     val4
#1  1 0.9470883 0.9014898 2.085935 3.460832
#2  2 1.8941766 0.9014898 2.085935 3.460832
#3  3 0.9470883 0.9014898 2.781247 3.460832
#4  4 1.8941766 0.9014898 2.781247 3.460832
#5  5 0.9470883 0.9014898 2.085935 4.152998
#6  6 1.8941766 0.9014898 2.085935 4.152998
#7  7 0.9470883 0.9014898 2.781247 4.152998
#8  8 1.8941766 0.9014898 2.781247 4.152998

Upvotes: 1

jogo
jogo

Reputation: 12569

The way to do this (without the column id) is:

mapply('*', df, c(mat))

Eventually convert to dataframe:

as.data.frame(mapply('*', df, c(mat)))

Example:

as.data.frame(mapply('*', cars, c(100, 1000)))

With respect to the column id you have a little bit to change:

my.cars <- cbind(id=1:nrow(cars), cars)
cbind(my.cars[1], as.data.frame(mapply('*', my.cars[-1], c(100, 1000))))

So in your case:

cbind(df[1], as.data.frame(mapply('*', df[-1], c(mat))))

Upvotes: 2

mra68
mra68

Reputation: 2960

df <- read.table( header=TRUE,
                  text = "id val1 val2 val3 val4
                    1    1    1    3    5
                    2    2    1    3    5
                    3    1    1    4    5
                    4    2    1    4    5
                    5    1    1    3    6
                    6    2    1    3    6
                    7    1    1    4    6
                    8    2    1    4    6")

M <- matrix( c(0.9470883,0.90148918,0.6953117,0.69216633), byrow=TRUE )

df[,-1] <- t( t(as.matrix(df[,-1])) * rep(t(M),nrow(df)) )

.

> df
  id      val1      val2     val3     val4
1  1 0.9470883 0.9014892 2.085935 3.460832
2  2 1.8941766 0.9014892 2.085935 3.460832
3  3 0.9470883 0.9014892 2.781247 3.460832
4  4 1.8941766 0.9014892 2.781247 3.460832
5  5 0.9470883 0.9014892 2.085935 4.152998
6  6 1.8941766 0.9014892 2.085935 4.152998
7  7 0.9470883 0.9014892 2.781247 4.152998
8  8 1.8941766 0.9014892 2.781247 4.152998
> 

Upvotes: 2

Related Questions