我正在尝试将
coxph
模型放入函数中,如下所示:
data(cancer, package="survival") # Import `mgus2` data
ndata <- expand.grid(sex=c("F", "M"), age=c(60, 80))
# Fit Cox PH model and run survfit
fit_cox <- function(df) {
msfit <- coxph(Surv(futime, death) ~ sex + age, data=df, id=id)
mssurv <- survfit(msfit, newdata=ndata)
}
fit_cox(mgus2)
如果我想将公式
Surv(futime, death) ~ sex + age
定义为字符串并使用 as.formula()
将其传递给我的模型,就会出现问题。
如果对
as.formula
的调用位于 fit_cox
函数之外,则对 survfit
的调用会中断:
my_formula <- as.formula("Surv(futime, death) ~ sex + age")
# Fit Cox PH model and run survfit
fit_cox <- function(df) {
msfit <- coxph(my_formula, data=df, id=id)
mssurv <- survfit(msfit, newdata=ndata)
}
> fit_cox(mgus2)
> Error in model.frame.default(formula = Surv(futime, death) ~ sex + age, :
> 'data' must be a data.frame, environment, or list
当对
as.formula
的调用移至 fit_cox
函数中时,不会出现此问题。
fit_cox <- function(df) {
my_formula <- as.formula("Surv(futime, death) ~ sex + age") # Moved this inside
msfit <- coxph(my_formula, data=df, id=id)
mssurv <- survfit(msfit, newdata=ndata)
}
> fit_cox(mgus2)
> # Successful
我想知道这是否不是与实现
survival
和 coxph
的 survfit
包有关的特定于包的问题。相反,它可能与 as.formula
通话有关。
将其放在函数内部而不是外部有什么区别?
解释为什么会发生这种情况很棘手,我不太确定我是否完全了解这里发生的情况,但解决方案是使用
do.call
来运行这样的函数:
fit_cox <- function(df) {
msfit <- do.call("coxph", list(formula=my_formula,
data=substitute(df),
id=as.name("id")))
mssurv <- survfit(msfit, newdata=ndata)
mssurv
}
该问题与调用的构造方式有关;在你的函数中,调用中有你的变量
do_cox1 <- function(df) {
coxph(my_formula, data=df, id=id)
}
do_cox1(mgus2)
# Call:
# coxph(formula = my_formula, data = df, id = id)
但是,如果使用
do.call
(首先计算结果),则可以使用 substitute
获取数据变量的名称,从而获得变量的实际值。
do_cox2 <- function(df) {
do.call("coxph", list(formula=my_formula,
data=substitute(df),
id=as.name("id")))
}
do_cox2(mgus2)
# Call:
# coxph(formula = Surv(futime, death) ~ sex + age, data = mgus2, id = id)
请参阅此答案了解另一个示例。
这是 R 中模型框架构建方式的一般“特征”。这是我们遇到麻烦时的调用堆栈:
where 1: model.frame.coxph(object)
where 2: stats::model.frame(object)
where 3: survfit.coxph(msfit, newdata = ndata)
where 4 at #3: survfit(msfit, newdata = ndata)
where 5: fit_cox(mgus2)
这是抛出错误的行:
mf <- eval(temp, environment(formula$terms), parent.frame())
temp
是未评估的模型框架调用,该包已根据其目的对其进行了修改:stats::model.frame(formula = Surv(futime, death) ~ sex + age,
data = df, id = id, xlev = list(sex = c("F", "M")))
parent.frame()
是调用当前函数的环境,即stats::model.frame()
的环境(参见上面的调用堆栈)environment(formula$terms)
是创建公式的环境,通常是 R 假设它可以找到公式中引用的所有内容的环境(如果不在父框架中)我还没有测试过,但添加了
assign("df", df, environment(my_formula))
你的功能可能会解决问题。