函数R作为参数,每个参数都是变量

时间:2022-06-26 16:04:33

In answer to a question on Cross Validated, 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, both fx and fy may require their own parameters. For instance, when fx=qchisq or when fy=qgamma. As a default solution, in my implementation, I used

然而,fx和fy可能都需要它们自己的参数。例如,当fx=qchisq或当fy=qgamma时。作为默认解决方案,在我的实现中,我使用了

fx=function(x) qchisq(x,df=3)

fx = function(x)qchisq(x,df = 3)

and

fy=function(x) qgamma(x,scale=.2)

财政年度(x)=函数qgamma(x,规模= 2)

but this is quite time consuming.

但这相当耗时。

For instance,

例如,

> 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 

versus

> 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 

2 个解决方案

#1


3  

An 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 displeased with the apparent necessity of as.list. I feel like I should know why that is, but it is escaping me at the moment.

我对显然有必要列出一份清单而感到不快。我觉得我应该知道为什么会这样,但现在我却无法理解。

In using this function, it should not be necessary to pass in all arguments, but you do need to make sure any list you pass to fx.args or fy.args is named.

在使用这个函数时,不需要传递所有参数,但是您需要确保传递给fx的任何列表。参数或财政年度。参数命名。

#2


1  

Thanks for the comments and answer! I fear the core issue is that, as pointed out by joran and Mr Flick, some quantile functions are much slower to execute than others:

谢谢你的评论和回复!我担心的核心问题是,正如joran和Flick指出的那样,一些分位数函数的执行速度要比其他函数慢得多:

> 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 

versus

> 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 the definition of the function when it requires parameters does seem as a straightforward and easy solution. Thanks for all of your inputs.

所以最后,当函数需要参数时使用函数的定义看起来是一个简单而简单的解决方案。谢谢你的建议。

#1


3  

An 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 displeased with the apparent necessity of as.list. I feel like I should know why that is, but it is escaping me at the moment.

我对显然有必要列出一份清单而感到不快。我觉得我应该知道为什么会这样,但现在我却无法理解。

In using this function, it should not be necessary to pass in all arguments, but you do need to make sure any list you pass to fx.args or fy.args is named.

在使用这个函数时,不需要传递所有参数,但是您需要确保传递给fx的任何列表。参数或财政年度。参数命名。

#2


1  

Thanks for the comments and answer! I fear the core issue is that, as pointed out by joran and Mr Flick, some quantile functions are much slower to execute than others:

谢谢你的评论和回复!我担心的核心问题是,正如joran和Flick指出的那样,一些分位数函数的执行速度要比其他函数慢得多:

> 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 

versus

> 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 the definition of the function when it requires parameters does seem as a straightforward and easy solution. Thanks for all of your inputs.

所以最后,当函数需要参数时使用函数的定义看起来是一个简单而简单的解决方案。谢谢你的建议。