therneau / survival

Survival package for R
381 stars 104 forks source link

Issue in `survresid.fit()` with finding `formula` and `data` objects (wrong environment?) #237

Closed DavidJesse21 closed 4 months ago

DavidJesse21 commented 8 months ago

Hi, I was planning to use survival::pseudo() inside of one of my own functions. I already encountered a similar issue as described in #178 and thus set model = TRUE in my survfit() call. However, it seems that there is another issue with survresid.fit() in that it tries to evaluate expressions using the wrong environment I guess. Below you can find a code example, which illustrates this issue further.

# Example data
df = survival::veteran
df = df[, c("time", "status", "trt")]
df$trt = df$trt - 1L

library(survival)

# Original usage/motivation: pseudo-observations ----

# "Manually" in the global environment (everything works)
fit = survfit(Surv(time, status) ~ trt, data = df, se.fit = FALSE, model = TRUE)
drop(pseudo(fit, times = 400, type = "rmst"))

# Inside of a function (does not work)
f = function(formula, data) {
  fit = survfit(formula, data = data, model = TRUE)
  drop(pseudo(fit, times = 400, type = "rmst"))
}
f(Surv(time, status) ~ trt, data = df)
# Error in x$formula : object of type 'closure' is not subsettable
# Error happens inside of `survresid.fit()`

# Try to track things down ----

# Function which fits a model inside (i.e. not in global environment)
f = function(formula, data) {
  fit = survfit(formula, data = data, model = TRUE, se.fit = FALSE)
  fit
}

# Obtain fit from that function
x = f(Surv(time, status) ~ trt, data = df)

# These are the deciding lines of code in `survresid.fit()`
Call = x$call
indx = match(
  c("formula", "data", "weights", "subset", "na.action", "istate", "id", "cluster", "etype"),
  names(Call), nomatch = 0
)
temp = Call[c(1, indx)]
temp[[1L]] = quote(stats::model.frame)
# And here the error happens
mf = eval.parent(temp)

# Make it work 
print(temp)
# stats::model.frame(formula = formula, data = data)
# Objects `formula` and `data` are needed (but are confused with the R functions)
formula = Surv(time, status) ~ trt
data = df
# Now this works
mf = eval.parent(temp)

Although I roughly know where this issue comes from, I cannot track it down entirely. I.e. I tried to create some hacky solutions for my functions to work, but didn't succeed yet. Your help would be appreciated!

Thanks David

therneau commented 4 months ago

This has been fixed in the most recent update