Я хочу выполнить поэлементное умножение двух больших матриц, я хочу сделать это максимально эффективно.
В настоящее время я использую базовый оператор *
Например, если у меня есть DF1, подобный следующему:
и DF2, подобный следующему:
DF1*DF2 приводит к
как я могу сделать это быстрее?
Имена DF1 и DF2 предполагают, что у вас есть фреймы данных, а не матрицы. Если бы они на самом деле были матрицами, умножение было бы быстрее, поэтому используйте as.matrix, чтобы сначала преобразовать каждую из них в матрицы, а затем выполнить умножение.
Ниже представлено несколько возможных вариантов, и вы сможете выбрать тот, который вам по душе.
Для скорости можете попробовать метод в f3()
set.seed(0)
A <- as.data.frame(matrix(runif (100), 10, 10))
B <- as.data.frame(matrix(runif (100), 10, 10))
f1 <- function() A * B
f2 <- function() as.data.frame(as.matrix(A) * as.matrix(B))
f3 <- function() as.data.frame(`dim<-`(unlist(A, FALSE, FALSE) * unlist(B, FALSE, FALSE), dim(A)))
f4 <- function() list2DF(Map(`*`, A, B))
microbenchmark(
f1(),
f2(),
f3(),
f4(),
check = "equal",
unit = "relative"
)
и ты увидишь
Unit: relative
expr min lq mean median uq max neval
f1() 19.315789 18.795854 9.927453 16.090020 14.320574 1.0078119 100
f2() 5.318182 5.192839 3.243506 4.736301 4.274322 0.7957232 100
f3() 1.000000 1.000000 1.000000 1.000000 1.000000 1.0000000 100
f4() 3.533493 3.342965 2.057707 2.988258 2.640750 0.6603172 100
Если вам не нужно сохранять оба A
и B
, вы можете обновить один из них по ссылке с помощью collapse::setop
, что будет быстрее, чем любая базовая версия A*B
. Разница во времени более очевидна при использовании больших матриц:
library(collapse)
set.seed(0)
A <- as.data.frame(matrix(runif (1e4), 100, 100))
B <- as.data.frame(matrix(runif (1e4), 100, 100))
f1 <- function() A * B
f2 <- function() as.data.frame(as.matrix(A) * as.matrix(B))
f3 <- function() as.data.frame(`dim<-`(unlist(A, FALSE, FALSE) * unlist(B, FALSE, FALSE), dim(A)))
f4 <- function() list2DF(Map(`*`, A, B))
f5 <- function() setop(AA, "*", B)
Для теста нам нужно добавить setup = {AA <- A*1}
, потому что AA
обновляется по ссылке каждый раз, когда вызывается f5
.
microbenchmark::microbenchmark(
f1(),
f2(),
f3(),
f4(),
f5(),
setup = {AA <- A*1},
check = "equal",
unit = "relative"
)
#> Unit: relative
#> expr min lq mean median uq max neval
#> f1() 246.80887 269.968102 229.09017 334.57839 333.18018 16.703191 100
#> f2() 53.29693 51.886762 46.97326 52.85084 75.09009 6.544267 100
#> f3() 10.31741 9.972887 12.58650 10.11263 13.70399 16.416862 100
#> f4() 35.90785 34.858054 36.90257 38.21005 57.01931 5.161036 100
#> f5() 1.00000 1.000000 1.00000 1.00000 1.00000 1.000000 100
оператор base * это так медленно?