Fastest Way to Multiply Matrix Columns with Vector Elements in R

Fastest way to multiply matrix columns with vector elements in R

Use some linear algebra and perform matrix multiplication, which is quite fast in R.

eg

m %*% diag(v)

some benchmarking

m = matrix(rnorm(1200000), ncol=6)

v=c(1.5, 3.5, 4.5, 5.5, 6.5, 7.5)
library(microbenchmark)
microbenchmark(m %*% diag(v), t(t(m) * v))
## Unit: milliseconds
## expr min lq median uq max neval
## m %*% diag(v) 16.57174 16.78104 16.86427 23.13121 109.9006 100
## t(t(m) * v) 26.21470 26.59049 32.40829 35.38097 122.9351 100

Fastest way for multiplying a matrix to a vector

sweep seems to run a bit faster on my machine

sweep(mat, 2, v, FUN = "*")

Some benchmarks:

> microbenchmark(mat %*% diag(v),sweep(mat, 2, v, FUN = "*"))

Unit: milliseconds
expr min lq median uq max neval
%*% 214.66700 226.95551 231.2366 255.78493 349.1911 100
sweep 42.42987 44.72254 62.9990 70.87403 127.2869 100

Fastest way to hadamard multiply all matrix columns with another matrix

You can try apply(A, 2, '*', B) and to come the the same like colmat_prod use array(apply(A, 2, '*', B), c(dim(B), ncol(A))):

identical(array(apply(A, 2, '*', B), c(dim(B), ncol(A))), colmat_prod(A, B))
#[1] TRUE

Another option is to use rep for the columns of A:

array(A[,rep(seq_len(ncol(A)), each=ncol(B))] * as.vector(B), c(dim(B), ncol(A)))

Timings:

library(microbenchmark)
microbenchmark(colmat_prod(A1, B1),
colmat_prod_vec(A1, B1),
array(apply(A1, 2, '*', B1), c(dim(B1), ncol(A1))),
array(A1[,rep(seq_len(ncol(A1)), each=ncol(B1))] * as.vector(B1), c(dim(B1), ncol(A1))),
times = 10)
#Unit: milliseconds
# expr min lq mean median uq max neval cld
# colmat_prod(A1, B1) 831.5437 857.0305 910.5694 878.6842 999.5354 1025.0915 10 c
# colmat_prod_vec(A1, B1) 981.9241 1010.9482 1174.1700 1162.7004 1319.3478 1444.6158 10 d
# array(apply(A1, 2, "*", B1), c(dim(B1), ncol(A1))) 716.1469 725.7862 765.4987 732.2520 789.3843 907.4417 10 b
# array(A1[, rep(seq_len(ncol(A1)), each = ncol(B1))] * as.vector(B1), c(dim(B1), ncol(A1))) 404.8460 406.2848 430.4043 428.2685 458.9400 462.0634 10 a

Multiplying columns in a matrix by a scalar in R

Another base R option using %*% and diag

> mat %*% diag(scalar)
[,1] [,2] [,3]
[1,] 1 8 21
[2,] 2 10 24
[3,] 3 12 27

multiply each columns of a matrix by a vector

vect*mat
[,1] [,2] [,3] [,4]
[1,] 2 8 14 20
[2,] 4 10 16 22
[3,] 6 12 18 24

The vector vect is recycled by column. Better to experiment with different values to see the process.

Multiply elements of a matrix with vector values

First you need to coerce coords to a matrix for indexing, then reverse the column order. Then it's just a simple lapply() loop.

coords <- as.matrix(coords)[, 2:1]
lapply(multis, function(x) {
M[coords] <- M[coords] * x
M
})

resulting in

[[1]]
[,1] [,2] [,3] [,4] [,5]
[1,] 0.1 5 9 13.0 17.0
[2,] 2.0 6 10 1.4 18.0
[3,] 3.0 7 11 15.0 1.9
[4,] 4.0 8 12 16.0 20.0

[[2]]
[,1] [,2] [,3] [,4] [,5]
[1,] 2 5 9 13 17
[2,] 2 6 10 28 18
[3,] 3 7 11 15 38
[4,] 4 8 12 16 20

[[3]]
[,1] [,2] [,3] [,4] [,5]
[1,] 100 5 9 13 17
[2,] 2 6 10 1400 18
[3,] 3 7 11 15 1900
[4,] 4 8 12 16 20

Multiply columns in a data frame by a vector

Transposing the dataframe works.

c1 <- c(1,2,3)
c2 <- c(4,5,6)
c3 <- c(7,8,9)
d1 <- data.frame(c1,c2,c3)
v1 <- c(1,2,3)
t(t(d1)*v1)
# c1 c2 c3
#[1,] 1 8 21
#[2,] 2 10 24
#[3,] 3 12 27

EDIT: If all columns are not numeric, you can do the following

c1 <- c(1,2,3)
c2 <- c(4,5,6)
c3 <- c(7,8,9)
d1 <- data.frame(c1,c2,c3)

# Adding a column of characters for demonstration
d1$c4 <- c("rr", "t", "s")

v1 <- c(1,2,3)

#Choosing only numeric columns
index <- which(sapply(d1, is.numeric) == TRUE)
d1_mat <- as.matrix(d1[,index])

d1[,index] <- t(t(d1_mat)*v1)
d1
# c1 c2 c3 c4
#1 1 8 21 rr
#2 2 10 24 t
#3 3 12 27 s

Multiply rows of matrix by vector?

I think you're looking for sweep().

# Create example data and vector
mat <- matrix(rep(1:3,each=5),nrow=3,ncol=5,byrow=TRUE)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3

vec <- 1:5

# Use sweep to apply the vector with the multiply (`*`) function
# across columns (See ?apply for an explanation of MARGIN)
sweep(mat, MARGIN=2, vec, `*`)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 2 4 6 8 10
[3,] 3 6 9 12 15

It's been one of R's core functions, though improvements have been made on it over the years.



Related Topics



Leave a reply



Submit