How much quicker do you need the element-wise multiplication to be?
On my system it takes on the order of 1/8 of a second to do this operation,
n <- 3.5e5
p <- 120
set.seed(123)
x <- matrix(runif(n * p), nrow = n)
y <- matrix(runif(n * p), nrow = n)
format(object.size(x), "MB")
#> [1] "320.4 Mb"
library(microbenchmark)
mbr <- microbenchmark(
R = x * y
)
mbr
#> Unit: milliseconds
#> expr min lq mean median uq max neval
#> R 106.9622 108.3356 124.0534 123.71 137.5286 153.561 100
Created on 2020-09-12 by the reprex package (v0.3.0)
How many times are you doing this element-wise matrix multiplication?
Even if the average time to do a single multiplication was 1 ns, doing 42 million of these multiplications would take 42 milliseconds a three-fold increase in speed over the {base} solution.
I do have C++ code which is a little faster than {base} at the expense of overwriting one of the input matrices. I'm on mobile right now, so I'll update this post with that code when I get home.
EDIT: Here is the faster C++ code,
library(microbenchmark)
n <- 3.5e5
p <- 120
set.seed(123)
.x <- matrix(runif(n * p), nrow = n)
.y <- matrix(runif(n * p), nrow = n)
This code is adapted from a solution found here:
https://stackoverflow.com/a/19920823
I've removed the creation of a new storage object to facilitate speeding up the function call.
Rcpp::cppFunction("NumericVector multMat(NumericMatrix m1, NumericVector m2) {
// modified from code found at:
// https://stackoverflow.com/a/19920823
m2 = m1 * m2;
return m2;
}")
(mbr <- microbenchmark(
R = x * y,
RCPP = multMat(x, y),
times = 100,
setup = y <- .y
))
#> Unit: milliseconds
#> expr min lq mean median uq max neval
#> R 106.8269 108.56660 124.9005 125.45150 138.30920 169.7719 100
#> RCPP 58.9489 59.62685 60.8673 60.10355 61.40645 73.7025 100
Created on 2020-09-12 by the reprex package (v0.3.0)
A word of warning, the y
object will be overwritten by the output object using this code. So it is only useful if you no longer need the original matrix after performing the multiplication. I had to include the setup =
argument in the microbenchmark()
call to reset the y
object to its original state.