【问题标题】:R function with functions as arguments, each with variable arguments以函数为参数的 R 函数,每个函数都有可变参数
【发布时间】:2015-07-14 09:30:45
【问题描述】:

在回复a question on Cross Validated 时,我写了a simple function,它使用任意分位数函数作为其参数

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)
  }

但是,fxfy 都可能需要它们自己的参数。例如,当fx=qchisqfy=qgamma 时。作为默认解决方案,在我的实现中,我使用了

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

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

但这很耗时。

例如,

> 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 

> 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 

【问题讨论】:

  • 我自己不会编写复杂的函数,但我认为您正在寻找... 语法:cran.r-project.org/doc/manuals/r-release/…
  • 我认为没有什么可以阻止您 (1) 在您的 ... 中为 etacor 包含 df.xdf.y,(2) 解析 ... 以获取这些和(3) 将解析出的值(如果找到)传递给fxfy。这很复杂,但这不应该太令人惊讶。
  • 没有什么能阻止你再拥有两个参数,每个参数都有fxfy 的参数列表,然后在函数中通过do.call 调用它们并构造一个列表论据。
  • 关于您的编辑......不知道为什么您认为评估 qexp 将花费与评估 qchisq 相同的时间。
  • 进一步@joran 的观点。看看x&lt;-runif(1000); microbenchmark::microbenchmark(qexp(x),(function(x){qexp(x)})(x), qchisq(x, 3), (function(x){qchisq(x, 3)})(x))。让事情变慢的不是function() 部分,而是您使用的是更复杂的分布。

标签: r function arguments simulation quantile


【解决方案1】:

我上面评论的插图:

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)
}

我对@9​​87654322@ 的明显必要性感到不满。我觉得我应该知道为什么会这样,但此刻它正在逃避我。

在使用此函数时,不必传入所有参数,但您需要确保您传递给fx.argsfy.args 的任何列表都已命名。

【讨论】:

    【解决方案2】:

    感谢 cmets 和回答!我担心核心问题是,正如joranMr 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 
    

    > 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 
    

    因此,最终在需要参数时使用函数的定义似乎是一个简单明了的解决方案。感谢您的所有投入。

    【讨论】:

      猜你喜欢
      • 2018-10-02
      • 1970-01-01
      • 1970-01-01
      • 2021-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多