【发布时间】:2013-07-12 14:43:45
【问题描述】:
解决方案现已上线 Rcpp Gallery
我从 RcppArmadillo 中的 mvtnorm 包中重新实现了 dmvnorm。我有点喜欢犰狳,但我想它也可以在普通的 Rcpp 中工作。 dmvnorm 的方法是基于马氏距离的,所以我有一个函数,然后是多元正态密度函数。
让我给你看我的代码:
#include <RcppArmadillo.h>
#include <Rcpp.h>
// [[Rcpp::depends("RcppArmadillo")]]
// [[Rcpp::export]]
arma::vec mahalanobis_arma( arma::mat x , arma::mat mu, arma::mat sigma ){
int n = x.n_rows;
arma::vec md(n);
for (int i=0; i<n; i++){
arma::mat x_i = x.row(i) - mu;
arma::mat Y = arma::solve( sigma, arma::trans(x_i) );
md(i) = arma::as_scalar(x_i * Y);
}
return md;
}
// [[Rcpp::export]]
arma::vec dmvnorm ( arma::mat x, arma::mat mean, arma::mat sigma, bool log){
arma::vec distval = mahalanobis_arma(x, mean, sigma);
double logdet = sum(arma::log(arma::eig_sym(sigma)));
double log2pi = 1.8378770664093454835606594728112352797227949472755668;
arma::vec logretval = -( (x.n_cols * log2pi + logdet + distval)/2 ) ;
if(log){
return(logretval);
}else {
return(exp(logretval));
}
}
所以,并没有让我大失所望:
模拟一些数据
sigma <- matrix(c(4,2,2,3), ncol=2)
x <- rmvnorm(n=5000000, mean=c(1,2), sigma=sigma, method="chol")
和基准测试
system.time(mvtnorm::dmvnorm(x,t(1:2),.2+diag(2),F))
user system elapsed
0.05 0.02 0.06
system.time(dmvnorm(x,t(1:2),.2+diag(2),F))
user system elapsed
0.12 0.02 0.14
不!!!! :-(
[编辑]
问题是: 1) 为什么 RcppArmadillo 实现比普通 R 实现慢? 2) 如何创建优于 R 实现的 Rcpp/RcppArmadillo 实现?
[编辑 2]
我将 mahalanobis_arma 放入 mvtnorm::dmvnorm 函数中,它也变慢了。
【问题讨论】:
-
我不明白你的问题是什么
-
如果大部分计算将由两个实现之间的同一个线性代数库执行,您为什么期望看到显着的改进?
-
这只是表明你可以用任何语言编写慢代码。 :) 为什么不简单地从 C++ 调用
mvtnorm::dmvnorm? -
您的问题标题具有误导性。 RCppArmadillo 不比 R 慢;它比 R 加 Fortran 慢。 Fortran 位恰好比 R 位更重要。
-
这一点的底线是,在低级语言中重新编码通常只有在相关操作还没有通过原始 R 函数中的已编译二进制代码时才有帮助 ...