问题
I'm trying to use purrr::safely with coxph so that I can capture error messages. I've made a safe version of coxph as follows
library(survival)
library(purrr)
coxph_safe <- safely(coxph)
This works perfectly when my only inputs are the formula and data, however, if I add another input such as subset or weights, I get the following error message:
simpleError in eval(substitute(subset), data, env): ..3 used in an incorrect context, no ... to look in
Does anyone know how to apply safely to coxph when additional inputs are required? I also get the same error using quietly instead of safely, and also if I make a safe version of lm and specify a subset. I'm using R 3.6.1 and purrr 0.3.2. For now, I've programmed a workaround, where I subset the data before applying coxph_safe, but it would be good to know if there was a better solution.
Here's a simple example:
test1 <- list(time=c(4,3,1,1,2,2,3),
status=c(1,1,1,0,1,1,0),
x=c(0,2,1,1,1,0,0),
sex=c(0,0,0,0,1,1,1))
# Without subset
coxph(Surv(time, status) ~ x, test1) # Works as expected
coxph_safe(Surv(time, status) ~ x, test1) # Works as expected
# With subset
coxph(Surv(time, status) ~ x, test1, subset = !sex) # Works as expected
coxph_safe(Surv(time, status) ~ x, test1, subset = !sex) # Error!
Edit
On a related note, I also get a similar error when applying anova to a coxph object generated via coxph_safe.
cox_1 <- coxph(Surv(time, status) ~ x, test1) # Works as expected
anova(cox_1) # Works as expected
cox_1s <- coxph_safe(Surv(time, status) ~ x, test1) # Works as expected
anova(cox_1s$result) # Error in is.data.frame(data) : ..2 used in an incorrect context, no ... to look in
As far as I can tell, this has something to do with how the call is stored. I can fix it by over-writing the call.
cox_1$call # coxph(formula = Surv(time, status) ~ x, data = test1)
cox_1s$result$call # .f(formula = ..1, data = ..2)
cox_1s$result$call <- cox_1$call
anova(cox_1s$result) # Now works as expected
Is there a better way around this?
回答1:
This actually has nothing to do with purrr::safely
. The issue is function nesting. Consider:
f <- function(...) {coxph(...)}
f(Surv(time, status) ~ x, test1) # Works
f(Surv(time, status) ~ x, test1, subset=!sex) # Error
The real reason for why it fails has to do with the behavior of substitute() inside nested functions. coxph()
uses substitute()
, and safely()
creates a nested function, leading to the scenario described in my link.
To address this issue, we need to wrap coxph()
into a function that properly handles non-standard evaluation (NSE):
coxph_nse <- function(...) {eval(rlang::expr(coxph( !!!rlang::enexprs(...) )))}
The new function no longer suffers the same nesting issues and can be safely passed to safely()
:
coxph_safe <- safely(coxph_nse)
coxph_safe(Surv(time, status) ~ x, test1) # works
cx1 <- coxph_safe(Surv(time, status) ~ x, test1, subset=!sex) # now also works!
anova(cx1$result) # works as well!
来源:https://stackoverflow.com/questions/57291701/how-do-i-use-safely-with-coxph-and-subset-or-weights