Reputation: 57
I am trying to find an efficient way to subset a matrix with Rcpp for a non-continuous set of rows and columns:
m <- matrix(1:20000000, nrow=5000)
rows <- sample(1:5000, 100)
cols <- sample(1:4000, 100)
In R, the matrix can be directly subsetted using the rows
and cols
vectors:
matrix_subsetting <- function(m, rows, cols){
return(m[rows, cols])
}
m[rows, cols]
# or
matrix_subsetting(m, rows, cols)
The fastest Rcpp way, I was able to find so far was:
Rcpp::cppFunction("
NumericMatrix cpp_matrix_subsetting(NumericMatrix m, NumericVector rows, NumericVector cols){
int rl = rows.length();
int cl = cols.length();
NumericMatrix out(rl, cl);
for (int i=0; i<cl; i++){
NumericMatrix::Column org_c = m(_, cols[i]-1);
NumericMatrix::Column new_c = out(_, i);
for (int j=0; j<rl; j++){
new_c[j] = org_c[rows[j]-1];
}
}
return(out);
}
")
But in comparison, the Rcpp version is significantly slower:
> microbenchmark::microbenchmark(matrix_subsetting(m, rows, cols), cpp_matrix_subsetting(m, rows, cols), times=500)
Unit: microseconds
expr min lq mean median uq max neval
matrix_subsetting(m, rows, cols) 23.269 90.127 107.8273 130.347 135.3285 605.235 500
cpp_matrix_subsetting(m, rows, cols) 69191.784 75254.277 88484.9328 90477.448 95611.9090 178903.973 500
Any ideas, to get at least a comparable speed with Rcpp?
I already tried the RcppArmadillo
arma::mat::submat
function, but it is slower than my version.
Solution:
Implementation of the cpp_matrix_subsetting
function with IntegerMatrix
instead of NumericMatrix
.
New benchmark:
> microbenchmark::microbenchmark(matrix_subsetting(m, rows, cols), cpp_matrix_subsetting(m, rows, cols), times=1e4)
Unit: microseconds
expr min lq mean median uq max neval
matrix_subsetting(m, rows, cols) 41.110 60.261 66.88845 61.730 63.8900 14723.52 10000
cpp_matrix_subsetting(m, rows, cols) 43.703 61.936 71.56733 63.362 65.8445 27314.11 10000
Upvotes: 3
Views: 1118
Reputation: 11728
This is because you have a matrix m
of type integer
(not double
as NumericMatrix
is expecting) so this makes a copy of the entire matrix (which takes a lot of time).
For example, try with m <- matrix(1:20000000 + 0, nrow=5000)
instead.
Upvotes: 7