Rcpp中二项似然的快速评估

Rcpp中二项似然的快速评估,r,rcpp,probability-distribution,log-likelihood,R,Rcpp,Probability Distribution,Log Likelihood,我需要快速评估大量的二项概率。因此,我正在考虑在Rcpp中实现这一点。一种方法是: #include <RcppArmadillo.h> // [[Rcpp::depends(RcppArmadillo)]] using namespace Rcpp; // [[Rcpp::export]] NumericVector eval_likelihood(arma::vec Yi, arma::vec Ni,

我需要快速评估大量的二项概率。因此,我正在考虑在Rcpp中实现这一点。一种方法是:

#include <RcppArmadillo.h>

// [[Rcpp::depends(RcppArmadillo)]]

using namespace Rcpp;

// [[Rcpp::export]]
NumericVector eval_likelihood(arma::vec Yi,
                              arma::vec Ni,
                              arma::vec prob){

  // length of vector
  int N = prob.n_rows;

  // storage for evaluated log likelihoods
  NumericVector eval(N);

  for(int ii = 0; ii < N; ii++){

  int y = Yi(ii); // no. of successes
  int n = Ni(ii); // no. of trials
  double p = prob(ii); // success probability

  eval(ii) = R::dbinom(y,n,p,true); // argument 4 is set to true to return log-likelihood

  }

  return eval;

}
总的来说,这是一个不错的结果。但是,矢量化的R解决方案平均比我的原始Rcpp解决方案略快:

microbenchmark::microbenchmark(R    = dbinom(Yi, Ni, probs, log = T),
                               Rcpp = eval_likelihood(Yi, Ni, probs))

Unit: microseconds
 expr     min      lq     mean   median       uq      max neval cld
    R 181.753 182.181 188.7497 182.6090 189.4515  286.100   100   a
 Rcpp 178.760 179.615 197.5721 179.8285 184.7470 1397.144   100   a

是否有人对更快地评估二项式日志可能性有一些指导?可能是更快的代码,也可能是概率论的黑客攻击。谢谢

您的实现看起来不错。由于R的
dbinom()
已经在高效的C代码中实现,您可能不会对其进行显著改进。我确实看到了一些可能会产生微小差异的事情(如果您经常这样做,可能会有所帮助):

  • 可以使用<代码> [II] < /C>而不是<代码>(ii)< /C> >避免边界检查,因为听起来你不需要担心这个问题(即,这不是用户调用的函数,它只在C++代码中调用,假设你的对象是这样设置的,这不会是问题)。
  • 您可以通过引用而不是通过值进行传递(例如,请参见)
因此,我添加了以下版本的函数:

/[[Rcpp::export]]
数值向量评估可能性2(常数arma::vec和Yi,
常数arma::vec和Ni,
常数arma::向量和概率){
//向量长度
int N=问题N_行;
//已评估日志可能性的存储
数值向量评估(N);
对于(int ii=0;ii
你可以看到我刚刚改变了这两件事

我还使用稍大一点的数据作为基准,不过我也为您最初的较小示例添加了基准:

Rcpp::sourceCpp(“so.cpp”)#源Rcpp脚本
#假数据
Yi=1:99999
Ni=2:100000
probs=runif(99999)
evalR=dbinom(Yi,Ni,probs,log=T)#R中的矢量化解
evalRcpp=eval_可能性(Yi,Ni,probs)#我的Rcpp解决方案
evalRCP2=评估可能性(Yi,Ni,probs)#我的Rcpp解决方案
相同(evalR,evalRcpp)
#[1]是的
相同(evalR、evalrcp2)
#[1]是的
微基准:微基准(R=dbinom(Yi,Ni,probs,log=T),
Rcpp=评估可能性(Yi,Ni,probs),
Rcpp2=评估可能性2(易学、易学、易学)
单位:毫秒
expr最小lq平均uq最大neval
R 7.427669 7.577011 8.565015 7.650762 7.916891 62.63154 100
Rcpp 7.368547 7.858408 8.884823 8.014881 8.353808 63.48417 100
Rcpp2 6.952519 7.256376 7.859609 7.376959 7.829000 12.51065 100
Yi=1:999
Ni=2:1000
probs=runif(999)
微基准:微基准(R=dbinom(Yi,Ni,probs,log=T),
Rcpp=评估可能性(Yi,Ni,probs),
Rcpp2=评估可能性2(易学、易学、易学)
单位:微秒
expr最小lq平均uq最大neval
R 90.073 100.5035 113.5084 109.5230 122.5260 188.304 100
Rcpp 90.188 97.8565 112.9082 105.2505 122.4255 172.975 100
Rcpp2 86.093 92.0745 103.9474 97.9380 113.2660 148.591 100

dbinom()
我认为您不太可能(至少在很大程度上)击败基本的R
dbinom()。R核心团队的成员已经用非常高效的C代码实现了所有类似的功能。这并不意味着你不能通过使用RCPP移动到C++来提高效率。但是,对
dbinom()
的简单调用并不是您要执行此操作的上下文。但是,“我需要非常快速地评估大量的二项式似然”听起来好像你的情况是把你的许多项目带给C++会提高效率。也许这是一个弱的形式:“DukMayr:可能性评估是一个更大的项目的一部分,我已经通过移动到C++获得了很好的效率收益。不过,在这种情况下,似乎不太可能击败R垒。那我就不得不忍受这个瓶颈了。感谢您指出,
dbinom
已经以高效的方式实现了!在这种情况下,从我所看到的,你的解决方案应该是好的。我不知道你的计算中的二项式似然部分会有多好,尽管也许其他人知道一个更好的实现。小事情可能是使用
[ii]
而不是
(ii)
来避免边界检查,通过引用而不是通过值传递(将显示基准测试这会带来适度的收益)谢谢,深思熟虑的回答+我学到了一些关于Rcpp效率的新知识!
microbenchmark::microbenchmark(R    = dbinom(Yi, Ni, probs, log = T),
                               Rcpp = eval_likelihood(Yi, Ni, probs))

Unit: microseconds
 expr     min      lq     mean   median       uq      max neval cld
    R 181.753 182.181 188.7497 182.6090 189.4515  286.100   100   a
 Rcpp 178.760 179.615 197.5721 179.8285 184.7470 1397.144   100   a