[R] Integration in R
Berend Hasselman
bhh at xs4all.nl
Tue Oct 2 19:21:16 CEST 2012
On 02-10-2012, at 17:23, Naser Jamil <jamilnaser79 at gmail.com> wrote:
> Dear R-users,
> I am facing problem with integrating in R a likelihood function which is a
> function of four parameters. It's giving me the result at the end but
> taking more than half an hour to run. I'm wondering is there any other
> efficient way deal with. The following is my code. I am ready to provide
> any other description of my function if you need to move forward.
>
> ------------------------------------------------------------------------------------------------------------------------------------
>
> library(cubature)
> dose<-c(2,3,5)
> y0<-c(2,1,0)
> y1<-c(1,1,1)
> y2<-c(0,1,2)
>
> lf<-function (x) {
> v<-1
> for (i in 1:length(dose)) {
> psi0<-1/((1+exp(x[1]+x[2]*dose[i]))*(1+exp(x[3]+x[4]*dose[i])))
>
> psi1<-exp(x[1]+x[2]*dose[i])/((1+exp(x[1]+x[2]*dose[i]))*(1+exp(x[3]+x[4]*dose[i])))
> v<-v*(psi0^y0[i])*(psi1^y1[i])*((1-psi0-psi1)^y2[i])
> }
> return(v)
> }
>
> adaptIntegrate(lf, lowerLimit = c(-20, 0,-20,0), upperLimit = c(0,10,0,10))
>
There are several things you could do.
1. Use the compiler package to make a compiled version of your function.
2. rewrite your function by putting x[1] etc. in separate variables x1, x2,... so avoiding the [..] indexing. You can do the same for dose[i].
And also compiling this version of the function.
3. do not recompute expressions such as exp(x1+x2*dose.i) several times. Store the result in a temporary variable and use that variable.
With these functions
library(compiler)
lf.c <- cmpfun(lf)
lf1 <-function (x) {
v<-1
x1 <- x[1]
x2 <- x[2]
x3 <- x[3]
x4 <- x[4]
for (i in 1:length(dose)) {
dose.i <- dose[i]
z1 <- exp(x1+x2*dose.i)
z2 <- exp(x3+x4*dose.i)
psi0<-1/((1+z1)*(1+z2))
psi1<-z1*psi0
v<-v*(psi0^y0[i])*(psi1^y1[i])*((1-psi0-psi1)^y2[i])
}
return(v)
}
lf1.c <- cmpfun(lf1)
I tested relative speeds with this code (small tolerance and max. function evaluations)
library(rbenchmark)
f1 <- function() adaptIntegrate(lf , lowerLimit = c(-20, 0,-20,0), upperLimit = c(0,10,0,10), tol=1e-3,maxEval=50000)
f2 <- function() adaptIntegrate(lf.c , lowerLimit = c(-20, 0,-20,0), upperLimit = c(0,10,0,10), tol=1e-3,maxEval=50000)
f3 <- function() adaptIntegrate(lf1 , lowerLimit = c(-20, 0,-20,0), upperLimit = c(0,10,0,10), tol=1e-3,maxEval=50000)
f4 <- function() adaptIntegrate(lf1.c, lowerLimit = c(-20, 0,-20,0), upperLimit = c(0,10,0,10), tol=1e-3,maxEval=50000)
benchmark(z1 <- f1(),z2 <- f2(), z3 <- f3(),z4 <- f4(),replications=1)
Result:
> benchmark(z1 <- f1(),z2 <- f2(), z3 <- f3(),z4 <- f4(),replications=1)
test replications elapsed relative user.self sys.self user.child
1 z1 <- f1() 1 3.197 4.535 3.177 0.008 0
2 z2 <- f2() 1 1.240 1.759 1.235 0.003 0
3 z3 <- f3() 1 2.171 3.079 2.167 0.002 0
4 z4 <- f4() 1 0.705 1.000 0.700 0.004 0
As you can see you should be able to get at least a fourfold speedup by using the compiled version of the optimized function.
I would certainly set tol and maxEval to something reasonable initially.
Checking that z1, z2, z3, and z4 are equal is left to you.
Finally, it may even be possible to eliminate the for loop in your function but I'll leave that for someone else.
Berend
More information about the R-help
mailing list