如何避免在此 R 代码中声明全局变量?

How can I avoid declaring a global variable in this R code?

我正在尝试修改 Kyle Gorman's autoloess 函数以作为 ggplot2stat_smooth 中的方法调用。 autoloess 是一个简单的包装器,它通过优化器运行 loess 以找到最小化 AICc 的 span 的值。

我创建了一些可以成功运行的东西,但只能使用全局变量。有没有更优雅、更惯用的编程方式?

我的代码:

AICc.loess <- function(fit) {
  # compute AIC_C for a LOESS fit, from:
  # 
  # Hurvich, C.M., Simonoff, J.S., and Tsai, C. L. 1998. Smoothing 
  # parameter selection in nonparametric regression using an improved 
  # Akaike Information Criterion. Journal of the Royal Statistical 
  # Society B 60: 271–293.
  # 
  # @param fit        loess fit
  # @return           'aicc' value
  stopifnot(inherits(fit, 'loess'))
  # parameters
  n <- fit$n
  trace <- fit$trace.hat
  sigma2 <- sum(resid(fit) ^ 2) / (n - 1)
  return(log(sigma2) + 1 + 2 * (2 * (trace + 1)) / (n - trace - 2))
}


.autoloess.magic.w <- NULL
autoloess <- function(formula, data, weights, span=c(0.01, 2.0)) {
  .autoloess.magic.w <- ~weights
  fit <- loess(formula=formula, 
               data=data, 
               weights=.autoloess.magic.w)
  stopifnot(length(span) == 2)
  # loss function in form to be used by optimize
  f <- function(span) AICc.loess(update(fit, span=span))
  # find best loess according to loss function
  res <- update(fit, span=optimize(f, span)$minimum)
  cat(paste("Optimal span:", res$pars$span, "\n"))
  return(res)
}

快速测试:

# Test
library(ggplot2)
set.seed(1984)
# Create a cubic curve
df <- data.frame(x=1:2500, y=500000 +
                   (-1000*(1:2500)) +
                   ((1:2500)^2)  +
                   -0.00025*((1:2500)^3) +
                   rnorm(2500, sd=60000),
                 ww=runif(2500, min=0, max=10))
# Use loess span
ggplot(df, aes(x=x, y=y, weight=ww)) + geom_point() + stat_smooth(method="loess")

# Use autoloess
ggplot(df, aes(x=x, y=y, weight=ww)) + geom_point() +  stat_smooth(method="autoloess")

您可以使用 weight 变量(调用函数时它似乎就在那里):

autoloess <- function(formula, data, weights, span=c(0.01, 2.0)) {

  fit <- loess(formula = formula, 
               data = data, 
               weights=weight)

  stopifnot(length(span) == 2)

  # loss function in form to be used by optimize
  f <- function(span) AICc.loess(update(fit, span=span))
  # find best loess according to loss function
  res <- update(fit, span=optimize(f, span)$minimum)
  cat(paste("Optimal span:", res$pars$span, "\n"))
  return(res)
}