В R матричное умножение очень оптимизировано, т.е. на самом деле это просто вызов BLAS/LAPACK. Тем не менее, я удивлен, что этот наивный C++ код для умножения матричных векторов кажется на 30% быстрее.
library(Rcpp)
# Simple C++ code for matrix multiplication
mm_code =
"NumericVector my_mm(NumericMatrix m, NumericVector v){
int nRow = m.rows();
int nCol = m.cols();
NumericVector ans(nRow);
double v_j;
for(int j = 0; j < nCol; j++){
v_j = v[j];
for(int i = 0; i < nRow; i++){
ans[i] += m(i,j) * v_j;
}
}
return(ans);
}
"
# Compiling
my_mm = cppFunction(code = mm_code)
# Simulating data to use
nRow = 10^4
nCol = 10^4
m = matrix(rnorm(nRow * nCol), nrow = nRow)
v = rnorm(nCol)
system.time(my_ans <- my_mm(m, v))
#> user system elapsed
#> 0.103 0.001 0.103
system.time(r_ans <- m %*% v)
#> user system elapsed
#> 0.154 0.001 0.154
# Double checking answer is correct
max(abs(my_ans - r_ans))
#> [1] 0
Занимает ли база R %*%
определенный тип проверки данных, которую я пропускаю?
EDIT: Поняв, что происходит (спасибо SO!), Стоит отметить, что это худший сценарий для R %*%
, т.е. Матрица по вектору. Например, @RalfStubner отметил, что использование RcppArmadillo даже быстрее, чем наивная реализация, но практически идентично для матричной матрицы умножить (когда обе матрицы большие и квадратные):
arma_code <-
"arma::mat arma_mm(const arma::mat& m, const arma::mat& m2) {
return m * m2;
};"
arma_mm = cppFunction(code = arma_code, depends = "RcppArmadillo")
nRow = 10^3
nCol = 10^3
mat1 = matrix(rnorm(nRow * nCol),
nrow = nRow)
mat2 = matrix(rnorm(nRow * nCol),
nrow = nRow)
system.time(arma_mm(mat1, mat2))
#> user system elapsed
#> 0.798 0.008 0.814
system.time(mat1 %*% mat2)
#> user system elapsed
#> 0.807 0.005 0.822
Таким образом, ток R (v3.5.0) %*%
близок к оптимальному для матричной матрицы, но может быть значительно ускорен для матричного вектора, если вы в порядке пропускаете проверку.