【问题标题】:How can you add (say a vectors name) to an object of type 'formula' within a function?如何在函数中向“公式”类型的对象添加(比如向量名称)?
【发布时间】:2012-01-20 18:43:58
【问题描述】:

这是我想做的一个非常精简的版本,我无法粘贴我的确切问题,因为代码太长太复杂,但我认为这是问题的根源。感谢 Josh 对这个问题的回答 How do you code an R function so that it 'knows' to look in 'data' for the variables in other arguments? 我已经成功了。

example <- function(model, xvar3=NULL, xvar4=NULL, data){
    print(class(model))
    #xvar3 <- eval(substitute(xvar3), envir=data, enclos=parent.frame())
    #xvar4 <- eval(substitute(xvar4), envir=data, enclos=parent.frame())
    print(class(xvar3))
    xvar5 <- xvar4^2
    mod <- glm( model + xvar3 + xvar5, data=data)    
    return(mod)
}

example(mpg ~ cyl, hp, wt, data=mtcars)

这失败了。如果您删除 cmets(基于上一个问题的帮助),它可以解决“查找”hp 和 wt 的问题。 'model' 是类公式,我希望它变成 'mpg ~ cyl + xvar3 + xvar5' 以便 glm 运行。但我似乎无法将它们添加到公式中。

我一直在玩弄“call”类,进一步玩弄“eval”和“as.formula”以及“paste”和“noquote”等的变体,但看不到让它坚持下去。

【问题讨论】:

  • 你可以在开始的 glm 上使用update....
  • 感谢 Hong,最初的尝试表明在其中打印“单词”xvar3(因为缺少正确的术语)而不是打印实际的数据向量存在同样的问题。这可能读起来很糟糕。
  • 重点是你想给模型添加更多的项。这就是update 的用途。看起来你基本上是在重新发明轮子。
  • 随意提出一个答案,说明更新在这种情况下如何工作,我无法让它适用于这个特定的设置。如果我正在寻找,我会重新发明轮子一个“新的”更新命令,我不是。我正在寻找一种方法来运行一次模型,并以所描述的方式添加“术语”。在我的实际问题中,这是在一个循环内,并且添加的变量不只 2 个(这只是一个简化的可重现示例),因此运行一个模型一次,然后多次更新,在一个循环内运行多次将是一个非常我的实际问题的低效方法。
  • @HongOoi - 关于update 的要点。尽管如此,环境仍然需要做一些工作才能使其在这种情况下工作。看我的回答。

标签: class r formula


【解决方案1】:

这是一种方法。我使用的技巧是根据给定的一个 + 两个额外的变量创建一个新公式。然后我对公式的环境做了一个技巧,这样xvar3/xvar5 和调用者本地的任何变量都可以使用。

glm 将始终在公式的环境和数据中查找变量(而不是其他任何地方!)。这就是为什么在这种情况下必须对公式环境进行一些操作的原因:它包含xvar3xvar5,并且父环境设置为原始公式的环境,以便也搜索变量(最后的foo例子)...

example <- function(model, xvar3=NULL, xvar4=NULL, data){
    e <- new.env(parent=environment(model))
    e$xvar3 <- eval(substitute(xvar3), envir=data, enclos=parent.frame())
    e$xvar4 <- eval(substitute(xvar4), envir=data, enclos=parent.frame())
    e$xvar5 <- e$xvar4^2

    model <- update(model, . ~ . + xvar3 + xvar5)
    environment(model) <- e

    mod <- glm(model, data=data)

    return(mod)
}

example(mpg ~ cyl, hp, wt, data=mtcars)

# Using a local variable should work too:
doit <- function(d) {
   foo <- d$cyl+1
   example(mpg ~ foo, hp, wt, data=d)
}
doit(mtcars)

【讨论】:

  • 编辑为使用 update 而不是直接与公式 call 对象混淆。
  • 我认为你最好操纵公式,而不是移动数据。
  • @hadley - 是的,如果你可以在公式中表达新数据(如wt^4 这里)......但如果你需要合并其他数据,你需要这样的东西。另一种方法是将xvar5 等新列添加到data.frame
【解决方案2】:

我会这样做:

add_vars <- function(model, xvar3=NULL, xvar4=NULL, data){
  # Capture the unevalated calls to xvar3 and xvar4
  xvar3 <- substitute(xvar3)
  xvar4 <- substitute(xvar4)

  # Use substitute to create the correct formula to supply to update
  update_f <- eval(substitute(. ~ . + xvar3 + I(xvar4 ^ 2), 
    list(xvar3 = xvar3, xvar4 = xvar4)))

  # Modify the original formula string
  update(model, update_f)
}

add_vars(mpg ~ cyl, hp, wt)
# mpg ~ cyl + hp + I(wt^2)

【讨论】:

    【解决方案3】:

    对此的另一种选择(来自同事):

    example <- function(model, xvar3=NULL, xvar4=NULL, data){
    
        data$xvar3 <- eval(substitute(xvar3), envir=data, enclos=parent.frame())
        data$xvar4 <- eval(substitute(xvar4), envir=data, enclos=parent.frame())
        data$xvar5 <- data$xvar4^2
    
        model <- as.formula(paste(model[2], paste(model[3], "xvar4","xvar5", sep="+"), sep="~"))
        mod <- glm(model, data=data)
        return(mod)
    }
    
    example(mpg ~ cyl, hp, wt, data=mtcars)
    

    我喜欢它,它很干净。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-06
      • 1970-01-01
      • 1970-01-01
      • 2021-05-27
      • 2010-11-07
      • 1970-01-01
      • 2012-10-22
      • 2013-06-01
      相关资源
      最近更新 更多