Search code examples
rparsingevalpasterandom-effects

paste formula together as.formula parse problem


I'm trying to paste a formula together to run in a model but I run into problems when I try to incorporate the random-effects. I want to define the random-effects separately and then add to the formula.

Simple working example without as.formula:

library(INLA)
data(Epil)
head(Epil)
##Define the model
formulae = y ~ Trt + Age + V4 + f(Ind, model = "iid") + f(rand, model = "iid")
formulae
# y ~ Trt + Age + V4 + f(Ind, model = "iid") + f(rand, model = "iid")
#WORKS
result = inla(formulae, family = "poisson", data = Epil, control.predictor = list(compute = TRUE))

Now if I want to make this more flexible where I can change the random-effects between models but not change the fixed effects, I tried something like this using as.formula:

test_vars = c("Trt",  "Age", "V4")
mm <- quote(
  f(Ind, model = 'iid') + f(rand, model = "iid")
)
mm
formula_2 <- as.formula(paste("y ~", paste(paste(test_vars, collapse = "+"), "+", mm)))
formula_2 #wont work here as expected
# y ~ Trt + Age + V4 + +y ~ Trt + Age + V4 + f(Ind, model = "iid")

formula_2 <- as.formula(paste("y ~", paste(paste(test_vars, collapse = "+"), "+", parse(text = mm))))
formula_2   #missing + f(rand, model = "iid")
# y ~ Trt + Age + V4 + +f(Ind, model = "iid")


result1 = inla(formula_2, family = "poisson", data = Epil, control.predictor = list(compute = TRUE))
identical(result, result1)
#FALSE

formula_2 is wrong and I just want a way of doing something like

formula_2 <- as.formula(paste("y ~", paste(paste(test_vars, collapse = "+"), "+", mm)))

where the desired output would be:

"y ~ Trt + Age + V4 + f(Ind, model = 'iid') + f(rand,model = 'iid')"

#where I can feed it directly into the model call:
result1 = inla(formula_2, family = "poisson", data = Epil, control.predictor = list(compute = TRUE))

I'd prefer to not directly manually quote ("f(Ind, model = 'iid') + f(rand, model = 'iid')") the random-effects as this masks the readability of it. I think parse or eval might help?

Thanks


Solution

  • I think this will do what you want

    as.formula(paste0("y ~ ", paste(paste(test_vars, collapse="+"), deparse(mm), sep="+")))
    # y ~ Trt + Age + V4 + f(Ind, model = "iid") + f(rand, model = "iid")
    

    Since you are building the formula as a string, we really need everything as a string rather than a quoted expression. So deparse will help turn that quoted expression into a string for easier manipulation.

    Rather than storing mm as a single quoted expression, it might be easier if you stored the additional terms you want as an expression collection. For example this would return the same thing

    mm <- expression(
      f(Ind, model = 'iid'),
      f(rand, model = "iid")
    )
    reformulate(c(test_vars, sapply(mm, deparse)), "y")