"object not found" inside a function: nlmer edition
Over the past few hours, I've found a few questions here regarding an R script that works fine outside of a function, but returns an "object not found" argument for an argument after refactoring the code to include functions. Unfortunately, the resolution for these errors seems to be very package and context dependent, so I have to throw my own nlmer-specific problem into the battle.
In short: I would like to run the nlmer model several times, but with a slightly different model specification each time. I have verified that the model works as stated outside of any function. I wrote a function that takes a data table and a formula (in string form) and runs the model, but returns an error that my model formula is "not found", although the variable "model_formula" is definitely in the function namespace.
Example:
# set up toy dataset
data <- data.table(patient_id=c(rep("pat_1", 10), rep("pat_2", 10), rep("pat_3", 10)),
agesero=c(rep(25,10), rep(19, 10), rep(34, 10)))
data$row <- as.numeric(rownames(data))
data[, variable:= ifelse(row%%10==0, "observed_survival", "vl")]
data[, M_visit_time:= ifelse(variable=="vl", row/6 + 0.25, 0)]
data[, value:= ifelse(variable=="vl", 3 + exp(-4*M_visit_time), row/10 + 2)]
data[, M_agesero:= ifelse(variable=="vl", agesero, 0)]
data[, D_intercept:= ifelse(variable=="observed_survival", 1, 0)]
data[, D_agesero:= ifelse(variable=="observed_survival", agesero, 0)]
data[, row:=NULL]
example_formula <- "value~ModelGradient(time=M_visit_time,b0,b2,b3)~M_agesero + D_intercept + D_agesero + (b0|patient_id)"
#this works, outside of a function:
Model<- ~b0+b2*exp(-b3*time)
ModelGradient<-deriv(Model,namevec=c("b0","b2","b3"),
function.arg=c("time","b0","b2","b3"))
out<-nlmer(as.formula(example_formula), data=data,
start = c(b0=3,b2=1,b3=4),
control=nlmerControl(optimizer="bobyqa", optCtrl=list(maxfun=200000)))
#but when I write a function:
run_nonlin<- function(model_formula, data){
Model<- ~b0+b2*exp(-b3*time)
ModelGradient<-deriv(Model,namevec=c("b0","b2","b3"),
function.arg=c("time","b0","b2","b3"))
print(paste("hello I am the model formula and I exist in this namespace! I am:",
model_formula))
out<-nlmer(as.formula(model_formula), data=data,
start = c(b0=3,b2=1,b3=4),
control=nlmerControl(optimizer="bobyqa",
optCtrl=list(maxfun=200000)))
return(out)
}
#and call:
function_output <- run_nonlin(model_formula=example_formula, data=data)
# I get the error:
# Error in as.formula(model_formula) : object 'model_formula' not found
As a side note, I did something very similar to this, no problem.
Any advice would be greatly appreciated.
(edited to include error message)
source to share
Seems to nlmer
have a weird way of parsing the formula you are passing to the function. You apparently cannot pass a variable that is not defined in the global environment. This seems to be happening because it nlformula
calls as.formula
on an unvalued symbol that runs like in a formula. This means the lexical scope is used for character resolution, so it looks model_formula
in the namespace stats
and then the global environment, not the scope defined by your function.
A workaround would be to evaluate this parameter and then pass that value through do.call()
, for example
run_nonlin<- function(model_formula, data){
Model<- ~b0+b2*exp(-b3*time)
ModelGradient<-deriv(Model,namevec=c("b0","b2","b3"),
function.arg=c("time","b0","b2","b3"))
out <- do.call('nlmer', list(as.formula(model_formula),
data=quote(data),
start = c(b0=3,b2=1,b3=4),
control=nlmerControl(optimizer="bobyqa",
optCtrl=list(maxfun=200000))))
return(out)
}
source to share