Rcpp中二项似然的快速评估
我需要快速评估大量的二项概率。因此,我正在考虑在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,
#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()我认为您不太可能(至少在很大程度上)击败基本的Rdbinom()。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