R with functions as arguments, each with variable arguments
In response to the Cross Validated question, I wrote a simple function that used arbitrary quantile functions as its arguments
etacor=function(rho=0,nsim=1e4,fx=qnorm,fy=qnorm){
#generate a bivariate correlated normal sample
x1=rnorm(nsim);x2=rnorm(nsim)
if (length(rho)==1){
y=pnorm(cbind(x1,rho*x1+sqrt((1-rho^2))*x2))
return(cor(fx(y[,1]),fy(y[,2])))
}
coeur=rho
rho2=sqrt(1-rho^2)
for (t in 1:length(rho)){
y=pnorm(cbind(x1,rho[t]*x1+rho2[t]*x2))
coeur[t]=cor(fx(y[,1]),fy(y[,2]))}
return(coeur)
}
However, fx
and fy
may require your own parameters. For example, when fx=qchisq
or when fy=qgamma
. As the default solution in my implementation, I used
fx=function(x) qchisq(x,df=3)
and
fy=function(x) qgamma(x,scale=.2)
but it takes a long time.
For example,
> rhos=seq(-1,1,.01)
> system.time(trancor<-etacor(rho=rhos,fx=qlnorm,fy=qexp))
utilisateur système écoulé
0.834 0.001 0.834
against
> system.time(trancor<-etacor(rho=rhos,fx=qlnorm,fy=function(x) qchisq(x,df=3)))
utilisateur système écoulé
8.673 0.006 8.675
source to share
Illustration of my comment above:
etacor1 <- function(rho = 0,
nsim = 1e4,
fx = qnorm,
fy = qnorm,
fx.args = formals(fx),
fy.args = formals(fy)){
#generate a bivariate correlated normal sample
x1 <- rnorm(nsim)
x2 <- rnorm(nsim)
fx.arg1 <- names(formals(fx))[1]
fy.arg1 <- names(formals(fy))[1]
if (length(rho) == 1){
y <- pnorm(cbind(x1, rho * x1 + sqrt((1 - rho^2)) * x2))
fx.args[[fx.arg1]] <- y[,1]
fy.args[[fy.arg1]] <- y[,2]
return(cor(do.call(fx,as.list(fx.args)),
do.call(fy,as.list(fy.args))))
}
coeur <- rho
rho2 <- sqrt(1 - rho^2)
for (t in 1:length(rho)){
y <- pnorm(cbind(x1,rho[t]*x1+rho2[t]*x2))
fx.args[[fx.arg1]] <- y[,1]
fy.args[[fy.arg1]] <- y[,2]
coeur[t] <- cor(do.call(fx,as.list(fx.args)),
do.call(fy,as.list(fy.args)))
}
return(coeur)
}
I am unhappy with the obvious need as.list
. I feel like I should know why this is so, but now it is eluding me.
When using this function, it is not necessary to pass all the arguments, but you do need to make sure that the list you pass to fx.args
or fy.args
is named.
source to share
Thanks for the comments and response! I'm afraid the main problem is that, as pointed out by joran and Mr Flick , some quantile functions are much slower than others:
> system.time(etacor(rhos,fx=function(x) qexp(x)))
utilisateur système écoulé
1.182 0.000 1.182
> system.time(etacor(rhos,fx=qexp))
utilisateur système écoulé
1.238 0.000 1.239
against
> system.time(etacor(rhos,fx=function(x) qchisq(x,df=3)))
utilisateur système écoulé
4.955 0.000 4.951
> system.time(etacor(rhos,fx=function(x) qgamma(x,sha=.3)))
utilisateur système écoulé
4.316 0.000 4.314
So in the end, using a function definition when it requires parameters seems like a simple and easy solution. Thanks for all your inputs.
source to share