gpt4 book ai didi

R - model.frame() 和非标准评估

转载 作者:行者123 更新时间:2023-12-04 09:41:03 27 4
gpt4 key购买 nike

我对我试图编写的函数的行为感到困惑。我的例子来自 survival package 但我认为这个问题比这更笼统。基本上,以下代码

library(survival)
data(bladder) ## this will load "bladder", "bladder1" and "bladder2"

mod_init <- coxph(Surv(start, stop, event) ~ rx + number, data = bladder2, method = "breslow")
survfit(mod_init)

将产生一个我感兴趣的对象。但是,当我在函数中编写它时,
my_function <- function(formula, data) {
mod_init <- coxph(formula = formula, data = data, method = "breslow")
survfit(mod_init)
}

my_function(Surv(start, stop, event) ~ rx + number, data = bladder2)

该函数将在最后一行返回错误:
 Error in eval(predvars, data, env) : 
invalid 'envir' argument of type 'closure'
10 eval(predvars, data, env)
9 model.frame.default(formula = Surv(start, stop, event) ~ rx +
number, data = data)
8 stats::model.frame(formula = Surv(start, stop, event) ~ rx +
number, data = data)
7 eval(expr, envir, enclos)
6 eval(temp, environment(formula$terms), parent.frame())
5 model.frame.coxph(object)
4 stats::model.frame(object)
3 survfit.coxph(mod_init)
2 survfit(mod_init)
1 my_function(Surv(start, stop, event) ~ rx + number, data = bladder2)

我很好奇是否有明显我遗漏的东西,或者这种行为是否正常。我觉得很奇怪,因为在 my_function 的环境中运行代码的第一部分时,我将拥有与全局环境中相同的对象。

编辑:我还收到了来自 survival 的作者 Terry Therneau 的有用输入。包裹。这是他的回答:

这个问题源于model.frame做的非标准评估。我发现的唯一解决方法是将 model.frame=TRUE 添加到原始 coxph 调用中。我认为这是 R 中的一个严重设计缺陷。非标准评估就像阴暗面——一条诱人且容易的道路,但总是以糟糕的结局告终。
特里 T。

最佳答案

诊断

从错误消息:

2 survfit(mod_init, newdata = base_case)
1 my_function(Surv(start, stop, event) ~ rx + number, data = bladder2)

问题显然不在于 coxph在模型拟合期间,但使用 survfit .

从这条消息中:
10 eval(predvars, data, env) 
9 model.frame.default(formula = Surv(start, stop, event) ~ rx +
number, data = data)

我可以说问题是在 survfit的早期阶段,函数 model.frame.default()找不到 模型架包含公式中使用的相关数据 Surv(start, stop, event) ~ rx + number .因此它提示。

什么是模型框架?

模型框架由 data 形成传递给拟合例程的参数,如 lm() , glm()mgcv:::gam() .它是一个与 data 行数相同的数据框, 但:
  • 删除所有未被 formula 引用的变量
  • 添加了很多属性,其中最重要的是envrionement

  • 大多数模型拟合例程,如 lm() , glm() , 和 mgcv:::gam() , 默认情况下将模型框架保留在其拟合对象中。这有一个好处,如果我们以后打电话 predict ,并且没有 newdata提供,它将从这个模型框架中找到数据进行评估。然而,一个明显的缺点是它会大大增加你的拟合对象的大小。

    然而, survival:::coxph()是个异常(exception)。默认情况下,它会 不是 将此类模型框架保留在其拟合对象中。嗯,很明显,这会使生成的拟合对象的尺寸小得多,但是,您会遇到遇到的问题。 如果我们想问survival:::coxph()保留此模型框架,然后使用 model = TRUE这个功能的。

    使用 survial:::coxph() 进行测试
    library(survival); data(bladder)

    my_function <- function(myformula, mydata, keep.mf = TRUE) {
    fit <- coxph(myformula, mydata, method = "breslow", model = keep.mf)
    survfit(fit)
    }

    现在,这个函数调用将失败,如您所见:
    my_function(Surv(start, stop, event) ~ rx + number, bladder2, keep.mf = FALSE)

    但是这个函数调用会成功:
    my_function(Surv(start, stop, event) ~ rx + number, bladder2, keep.mf = TRUE)

    lm() 的相同行为

    我们实际上可以在 lm() 中演示相同的行为:
    ## generate some toy data
    foo <- data.frame(x = seq(0, 1, length = 20), y = seq(0, 1, length = 20) + rnorm(20, 0, 0.15))

    ## a wrapper function
    bar <- function(myformula, mydata, keep.mf = TRUE) {
    fit <- lm(myformula, mydata, model = keep.mf)
    predict.lm(fit)
    }

    现在这将成功,通过保持模型框架:
    bar(y ~ x - 1, foo, keep.mf = TRUE)

    虽然这将失败,通过丢弃模型框架:
    bar(y ~ x - 1, foo, keep.mf = FALSE)

    使用参数 newdata ?

    请注意,我的示例 lm()有点人为,因为我们实际上可以使用 newdata参数在 predict.lm()解决这个问题:
    bar1 <- function(myformula, mydata, keep.mf = TRUE) {
    fit <- lm(myformula, mydata, model = keep.mf)
    predict.lm(fit, newdata = lapply(mydata, mean))
    }

    现在我们是否保留模型框架,两者都会成功:
    bar1(y ~ x - 1, foo, keep.mf = TRUE)
    bar1(y ~ x - 1, foo, keep.mf = FALSE)

    那么你可能想知道:我们可以对 survfit() 做同样的事情吗? ?
    survfit()是一个泛型函数,在你的代码中,你实际上是在调用 survfit.coxph() .确实有 newdata这个函数的参数。文档中写道:

    newdata:

    a data frame with the same variable names as those that appear in the ‘coxph’ formula. ... ... Default is the mean of the covariates used in the ‘coxph’ fit.



    所以,让我们试试:
    my_function1 <- function(myformula, mydata) {
    mtrace.off()
    fit <- coxph(myformula, mydata, method = "breslow")
    survival:::survfit.coxph(fit, newdata = lapply(mydata, mean))
    }

    我们希望这项工作:
    my_function1(Surv(start, stop, event) ~ rx + number, bladder2)

    但:
    Error in is.data.frame(data) (from #5) : object 'mydata' not found

    1: my_function1(Surv(start, stop, event) ~ rx + number, bladder2)
    2: #5: survival:::survfit.coxph(fit, lapply(mydata, mean))
    3: stats::model.frame(object)
    4: model.frame.coxph(object)
    5: eval(temp, environment(formula$terms), parent.frame())
    6: eval(expr, envir, enclos)
    7: stats::model.frame(formula = Surv(start, stop, event) ~ rx + number, data =
    8: model.frame.default(formula = Surv(start, stop, event) ~ rx + number, data
    9: is.data.frame(data)

    请注意,虽然我们传入了 newdata ,它不用于模型框架的构建:
    3: stats::model.frame(object)

    只有 object ,拟合模型的副本,传递给 model.frame.default() .

    这与 predict.lm() 中发生的情况大不相同。 , predict.glm()mgcv:::predict.gam() .在这些例程中, newdata传递给 model.frame.default() .例如,在 lm() , 有:
    m <- model.frame(Terms, newdata, na.action = na.action, xlev = object$xlevels)

    我不使用 survival包,所以不确定如何 newdata在这个包中工作。所以我认为我们真的需要一些专家来解释这一点。

    关于R - model.frame() 和非标准评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37364571/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com