Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在R中加速这个简单的函数_R_Performance - Fatal编程技术网

如何在R中加速这个简单的函数

如何在R中加速这个简单的函数,r,performance,R,Performance,我正在尝试使用R中的Conway–Maxwell Poisson回归 但是,对于大型数据集,它的速度非常慢。因此,我试图分析和检查源代码 大部分时间(>95%)花在函数COMPoissonReg:::computez,相当于: test <- function (lambda, nu, max=100) { forans <- matrix(0, ncol = max + 1, nrow = length(lambda)) for (j in 1:max) {

我正在尝试使用R中的Conway–Maxwell Poisson回归

但是,对于大型数据集,它的速度非常慢。因此,我试图分析和检查源代码

大部分时间(>95%)花在函数
COMPoissonReg:::computez
,相当于:

test <- function (lambda, nu, max=100) 
{
    forans <- matrix(0, ncol = max + 1, nrow = length(lambda))
    for (j in 1:max) {
        temp <- matrix(0, ncol = j, nrow = length(lambda))
        for (i in 1:j) {
            temp[, i] <- lambda/(i^nu)
        }
        for (k in 1:length(lambda)) {
            forans[k, j + 1] <- prod(temp[k, ])
        }
    }
    forans[, 1] <- rep(1, length(lambda))
    ans <- rowSums(forans)
    return(ans)
}
更新
我意识到另一个问题:浮点算术限制。做幂级数是危险的,它很快就会溢出,特别是当我们必须矢量化时。例如,
lambda^100
当然是
NAN
如果
lambda
>10000。如果我用其他语言编程,也许我会使用
reduce
,但我担心R reduce的速度很慢。

通过避免循环,您可以使它比您正在使用的函数快得多。例如:

test2<-function(lambda,nu,max=100){
  len<-length(lambda)
  mm<-matrix(rep(lambda,each=max+1),max+1,len)
  mm<-mm^(0:max)
  mm<-mm/factorial(0:max)^nu
  colSums(mm)
}

在@mrips之后,有时处理日志可能会快一点,因为您可以使用乘法而不是指数运算:

test4 <- function(lambda,nu,max=100){
  mm<-matrix(log(lambda),max,length(lambda), byrow=TRUE) 
  mm<-mm * 1:max  -  nu*lfactorial(1:max)
  1 + colSums(exp(mm))
}

好的,这是Rcpp的答案。正如所料,它比其他任何一种都快得多

require(Rcpp)
rcppfun<-"
Rcpp::NumericVector myfun(Rcpp::NumericVector lambda,
Rcpp::NumericVector weights)
{
  int num = lambda.size();
  int max = weights.size();
  std::vector<double> r(num);
  for(int i=0; i<num; i++){
    double total = 0;
    double prod = 1;
    for(int j=0; j<max; j++){
      total += prod/weights[j];
      prod *= lambda[i];
    }
    r[i]=total;
  }
  return Rcpp::wrap(r);
}
"
testRcpp<-cppFunction(rcppfun)
test5<-function(lambda,nu,max=100){
    wts<-factorial(0:max)^nu
    testRcpp(lambda,wts)    
}
在编辑中,这里还有一个Rcpp版本,它应该至少部分解决溢出问题,通过增量计算每个项,而不是单独计算分子和分母

rcppfun2<-"
Rcpp::NumericVector myfun2(Rcpp::NumericVector lambda, Rcpp::NumericVector nu){
int num = lambda.size();
int max = nu.size();
std::vector<double> r(num);
for(int i=0; i<num; i++){
  double term = 1;
  double total = 1;
  for(int j=0; j< max; j++){
    term *= (lambda[i]/nu[j]);
    total += term;
  }
  r[i]=total;
}
 return Rcpp::wrap(r);
}
"

testRcpp2<-cppFunction(rcppfun2)
test6<-function(lambda,nu,max=100){
    testRcpp2(lambda,(1:max)^nu)
}

> lam<-abs(rnorm(10000))
> max(abs(test2(lam,1.2)-test6(lam,1.2)))
[1] 1.065814e-14
> microbenchmark(test5(lam,1.2),test6(lam,1.2))
Unit: milliseconds
            expr      min       lq   median       uq      max neval
 test5(lam, 1.2) 3.416786 3.426013 3.435492 3.444196 3.604486   100
 test6(lam, 1.2) 3.554147 3.572285 3.580865 3.588030 3.840713   100

rcppfun2我在上面睡了一觉,想到了另一个很大的改进,如果你能使用gsl软件包的话。你要做的就是计算一个多项式:

require(gsl)
test5 <- function(lambda, nu, max=100){
gsl_poly(factorial(0:max)^-nu, lambda)
}

R>microbenchmark(test2(1:50,5.1), test4(1:50,5.1), test5(1:50,5.1))
Unit: microseconds
             expr      min        lq    median        uq       max neval
 test2(1:50, 5.1) 4518.957 4838.5185 5318.5040 5617.6330 19978.039   100
 test4(1:50, 5.1) 2043.422 2268.3490 2472.0430 2727.1045 10328.376   100
 test5(1:50, 5.1)  311.144  407.2465  476.0755  540.6095  1138.766   100
require(gsl)
测试5微基准(测试2(1:50,5.1)、测试4(1:50,5.1)、测试5(1:50,5.1))
单位:微秒
expr最小lq中值uq最大neval
测试2(1:50,5.1)4518.957 4838.5185 5318.5040 5617.6330 19978.039 100
测试4(1:50,5.1)2043.422268.3490 2472.0430 2727.1045 10328.376 100
测试5(1:50,5.1)311.144407.2465476.0755540.60951138.766100

谢谢,我想知道我们是否可以使用
cumprod
,而不必承担
apply
的负担,因为我需要进一步的10倍改进,以使其能够很好地处理我的数据集。在R中,10倍将很难。我想看看
Rcpp
,它很容易使用,而且可能会给你带来你想要的改进。我建议你看看
Rcpp
。重写
computez
函数应该不是很难。没有意义的标题,你应该编辑它,你添加的假设(数据需要是正的)没有真正显著的改进,其中长度(lambda)=1e4。lambda对于泊松分布是正的。看起来与
testRcpp2
非常相似!
R>microbenchmark(test2(1:50,5), test4(1:50,5))
Unit: microseconds
           expr     min        lq    median        uq      max neval
 test2(1:50, 5) 952.360 1432.6600 1436.4525 1440.1860 3467.981   100
 test4(1:50, 5) 695.189 1041.4785 1042.8315 1045.6525 2970.441   100
require(Rcpp)
rcppfun<-"
Rcpp::NumericVector myfun(Rcpp::NumericVector lambda,
Rcpp::NumericVector weights)
{
  int num = lambda.size();
  int max = weights.size();
  std::vector<double> r(num);
  for(int i=0; i<num; i++){
    double total = 0;
    double prod = 1;
    for(int j=0; j<max; j++){
      total += prod/weights[j];
      prod *= lambda[i];
    }
    r[i]=total;
  }
  return Rcpp::wrap(r);
}
"
testRcpp<-cppFunction(rcppfun)
test5<-function(lambda,nu,max=100){
    wts<-factorial(0:max)^nu
    testRcpp(lambda,wts)    
}
> lam<-abs(rnorm(10000))
> max(abs(test5(lam,1.2)-test2(lam,1.2)))
[1] 7.105427e-15
> microbenchmark(test2(lam,1.2),test3(lam,1.2),test4(lam,1.2),test5(lam,1.2))
Unit: milliseconds
            expr        min         lq     median         uq        max neval
 test2(lam, 1.2) 125.601616 126.790516 127.700099 135.182263 222.340179   100
 test3(lam, 1.2) 125.523424 126.666410 126.921035 131.316254 178.633839   100
 test4(lam, 1.2)  41.734015  42.640340  43.190553  50.932952  97.765219   100
 test5(lam, 1.2)   3.432029   3.501046   3.519007   3.532603   3.754232   100
rcppfun2<-"
Rcpp::NumericVector myfun2(Rcpp::NumericVector lambda, Rcpp::NumericVector nu){
int num = lambda.size();
int max = nu.size();
std::vector<double> r(num);
for(int i=0; i<num; i++){
  double term = 1;
  double total = 1;
  for(int j=0; j< max; j++){
    term *= (lambda[i]/nu[j]);
    total += term;
  }
  r[i]=total;
}
 return Rcpp::wrap(r);
}
"

testRcpp2<-cppFunction(rcppfun2)
test6<-function(lambda,nu,max=100){
    testRcpp2(lambda,(1:max)^nu)
}

> lam<-abs(rnorm(10000))
> max(abs(test2(lam,1.2)-test6(lam,1.2)))
[1] 1.065814e-14
> microbenchmark(test5(lam,1.2),test6(lam,1.2))
Unit: milliseconds
            expr      min       lq   median       uq      max neval
 test5(lam, 1.2) 3.416786 3.426013 3.435492 3.444196 3.604486   100
 test6(lam, 1.2) 3.554147 3.572285 3.580865 3.588030 3.840713   100
require(gsl)
test5 <- function(lambda, nu, max=100){
gsl_poly(factorial(0:max)^-nu, lambda)
}

R>microbenchmark(test2(1:50,5.1), test4(1:50,5.1), test5(1:50,5.1))
Unit: microseconds
             expr      min        lq    median        uq       max neval
 test2(1:50, 5.1) 4518.957 4838.5185 5318.5040 5617.6330 19978.039   100
 test4(1:50, 5.1) 2043.422 2268.3490 2472.0430 2727.1045 10328.376   100
 test5(1:50, 5.1)  311.144  407.2465  476.0755  540.6095  1138.766   100