R 编程:当对象存在于多个环境中时计算表达式



简短版本

具有两个变量 xy 的表达式,其中 x 包含在环境 1 中y包含在第二个环境中。 程序员如何评估表达?

详细版本

我有一个函数,它将formula和数据帧作为参数。 在formula的右侧是对函数的调用 splines::bs生成 B 样条基础。 主力功能做了几件事,其中之一这需要从公式中提取bs调用并对其进行评估。 这我试图解决的问题涉及在参数时评估bs调用值包含在不同的环境中。

以下是重现我正在处理的问题所需的函数

library(splines)
extract_bmat <- function(form) { 
  B <- NULL
  rr <- function(x) { 
    if (is.call(x) && grepl("bs", deparse(x[[1]]))) { 
      B <<- x 
    } else if (is.recursive(x)) { 
      as.call(lapply(as.list(x), rr))
    } else {
      x
    }
  } 
  z <- lapply(as.list(form), rr)
  B
}
some_workhorse <- function(formula, data) { 
  # ... lots of cool stuff ... 
  # fit <- lm(formula, data) 
  bmat <- eval(extract_bmat(formula), data)
  bmat
}
# The following works when evaluated in the .GlobalEnv
# The eval(extract_bmat(formula), data) call within the some_workhorse
# function works without errors
xi      <- c(3, 4.5)
eg_data <- data.frame(x = 1:10, y = sin(1:10)) 
some_workhorse(y ~ bs(x, knots = xi), data = eg_data)

现在,如果函数some_workhorse并且xi向量和eg_data 在函数环境中生成的data.frame会导致错误。

foo <- function() { 
  xi_in_foo      <- c(2, 3)
  eg_data_in_foo <- data.frame(x = 1:10, y = sin(1:10)) 
  some_workhorse(y ~ bs(x, knots = xi_in_foo), data = eg_data_in_foo)
}
foo()
# Error in sort(c(rep(Boundary.knots, ord), knots)) :
#   object 'xi_in_foo' not found

错误的位置在splines::bs调用内,但这不是重要部分; 未找到xi_in_foo是要解决的重要问题。

我知道这个问题与我在 R 中对环境的处理不当有关。 我主要问题是

  • eval(extract_bmat(formula), data)呼叫应该如何在 编写some_workhorse函数,使其在调用时正常工作.GlobalEnv还是何时在函数环境中调用?

次要问题:

  • extract_bmat函数中,我更愿意定义一个环境用于B并使用assign而不是<<-。 我怀疑<<-是最好的选项,因为发生的递归水平存在不确定性。也就是说,我希望看到其他解决方案。

感谢您的帮助。

你应该将你的函数定义为

some_workhorse <- function(formula, data) { 
  # ... lots of cool stuff ... 
  # fit <- lm(formula, data) 
  bmat <- eval(extract_bmat(formula), data, environment(formula))
  bmat
}

请注意,R 中的formula捕获创建它们的环境。只要定义公式的环境中存在xi_in_foo,这应该有效。变量将首先在data列表/data.frame 中查找,然后将公式环境用作封闭环境。如果您不使用公式,有时人们使用 parent.frame() 作为 enclos= 参数,以便在调用函数的环境中查找变量,而不是将函数定义为 R 词法范围的默认值。

最新更新