Rcpp中的矩阵乘法 [英] Matrix multiplication in Rcpp

查看:393
本文介绍了Rcpp中的矩阵乘法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我是新手用户,所以请忘记我的一般无知。我正在寻找R中%*%运算符的一种更快的替代方法。尽管较早的帖子建议使用RcppArmadillo,但我已经尝试了2个小时使RcppArmadillo正常工作。我经常遇到词汇问题,这些错误会产生意外……错误。我已经在Rcpp中找到了可以执行的以下功能:

First of all, I am a novice user so forget my general ignorance. I am looking for a faster alternative to the %*% operator in R. Even though older posts suggest the use of RcppArmadillo, I have tried for 2 hours to make RcppArmadillo work without success. I always run into lexical issues that yield 'unexpected ...' errors. I have found the following function in Rcpp which I do can make work:

library(Rcpp)
func <- '
NumericMatrix mmult( NumericMatrix m , NumericMatrix v, bool  byrow=true )
{
  if( ! m.nrow() == v.nrow() ) stop("Non-conformable arrays") ;
  if( ! m.ncol() == v.ncol() ) stop("Non-conformable arrays") ;

  NumericMatrix out(m) ;

  for (int i = 0; i < m.nrow(); i++) 
  {
  for (int j = 0; j < m.ncol(); j++) 
  {
  out(i,j)=m(i,j) * v(i,j) ;
  }
  }
  return out ;
}
'

此函数执行逐元素乘法并不表现为%*%。有没有简单的方法可以修改上面的代码以达到预期的结果?

This function, however, performs element-wise multiplication and does not behave as %*%. Is there an easy way to modify the above code to achieve the intended result?

编辑:

我有拿出一个使用RcppEigen的函数似乎胜过%*%:

I have come up with a function using RcppEigen that seems to beat %*%:

etest <- cxxfunction(signature(tm="NumericMatrix",
                           tm2="NumericMatrix"),
                 plugin="RcppEigen",
                 body="
NumericMatrix tm22(tm2);
NumericMatrix tmm(tm);

const Eigen::Map<Eigen::MatrixXd> ttm(as<Eigen::Map<Eigen::MatrixXd> >(tmm));
const Eigen::Map<Eigen::MatrixXd> ttm2(as<Eigen::Map<Eigen::MatrixXd> >(tm22));

Eigen::MatrixXd prod = ttm*ttm2;
return(wrap(prod));
                 ")

set.seed(123)
M1 <- matrix(sample(1e3),ncol=50)
M2 <- matrix(sample(1e3),nrow=50)

identical(etest(M1,M2), M1 %*% M2)
[1] TRUE
res <- microbenchmark(
+   etest(M1,M2),
+   M1 %*% M2,
+   times=10000L)

res

Unit: microseconds
         expr    min    lq      mean median     uq    max neval
 etest(M1, M2)  5.709  6.61  7.414607  6.611  7.211 49.879 10000
     M1 %*% M2 11.718 12.32 13.505272 12.621 13.221 58.592 10000


推荐答案

有充分的理由依靠现有的库/包来执行标准任务。库中的例程

There are good reasons to rely on existing libraries / packages for standard tasks. The routines in the libraries are


  • 已优化

  • 经过全面测试

  • 保持代码紧凑,易于阅读且易于维护的好方法。

因此,我认为使用RcppArmadillo此处最好使用RcppEigen或RcppEigen。但是,为回答您的问题,下面是一个可能的Rcpp代码,用于执行矩阵乘法:

Therefore I think that using RcppArmadillo or RcppEigen should be preferable here. However, to answer your question, below is a possible Rcpp code to perform a matrix multiplication:

library(Rcpp)
cppFunction('NumericMatrix mmult(const NumericMatrix& m1, const NumericMatrix& m2){
if (m1.ncol() != m2.nrow()) stop ("Incompatible matrix dimensions");
NumericMatrix out(m1.nrow(),m2.ncol());
NumericVector rm1, cm2;
for (size_t i = 0; i < m1.nrow(); ++i) {
    rm1 = m1(i,_);
    for (size_t j = 0; j < m2.ncol(); ++j) {
      cm2 = m2(_,j);
      out(i,j) = std::inner_product(rm1.begin(), rm1.end(), cm2.begin(), 0.);              
    }
  }
return out;
}')

让我们测试一下:

A <- matrix(c(1:6),ncol=2)
B <- matrix(c(0:7),nrow=2)
mmult(A,B)
#     [,1] [,2] [,3] [,4]
#[1,]    4   14   24   34
#[2,]    5   19   33   47
#[3,]    6   24   42   60
identical(mmult(A,B), A %*% B)
#[1] TRUE

希望这会有所帮助。

如基准测试所示,上面的Rcpp代码比R的内置%*%运算符要慢。我认为,尽管我的Rcpp代码肯定可以改进,但是就性能而言,在%*%之后很难超越优化的代码:

As benchmark tests show, the above Rcpp code is slower than R's built-in %*% operator. I assume that, while my Rcpp code can certainly be improved, it will be hard to beat the optimized code behind %*% in terms of performance:

library(microbenchmark)
set.seed(123)    
M1 <- matrix(rnorm(1e4),ncol=100)
M2 <- matrix(rnorm(1e4),nrow=100)
identical(M1 %*% M2, mmult(M1,M2))
#[1] TRUE
res <- microbenchmark(
             mmult(M1,M2),
             M1 %*% M2,
             times=1000L)
#> res 
#Unit: microseconds
#          expr      min        lq      mean    median        uq      max neval cld
# mmult(M1, M2) 1466.855 1484.8535 1584.9509 1494.0655 1517.5105 2699.643  1000   b
#     M1 %*% M2  602.053  617.9685  687.6863  621.4335  633.7675 2774.954  1000  a

这篇关于Rcpp中的矩阵乘法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆