该解决方案现已在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 函数中,它也变慢了。