1

In R I often need to cycle through a list of lm type objects (e.g. glm, lme, clm) and update them with a new formula or other arguments. I do this using lapply() because it returns them in the same list format with names intact, so I can continue the process.

Sometimes the argument I pass is dynamic and varies for each model. For example,

lapply(names(mylist) function(ii) {
  jj<-myotherlist[[ii]]; 
  update(mylist[[ii]],.~.+jj)
}) 

where jj is a term that gets added to each model in the list, and is defined in some other list on a per-model basis.

Let's say the intended result formula for a particular model was supposed to be y~a+b+c. Instead of that, the call object inside the resulting lm object contains y~a+b+jj. So, in some circumstances the resulting lm object behaves normally, but whenever the formula needs to be evaluated, it errors out because jj is long gone. Is there a recommended way to either force update() to expand all the variables among its arguments when it writes the call object in its output or to force functions that use the call object to evaluate the call in the lm object's internal context instead of the global context, so that at least I can stuff the new variables into the model or data object that lm style objects typically contain?

AND, what if the part that gets updated with a dynamic variable is the data argument? E.g.:

data=cbind(sharedByAllModels,y=kk)

...where kk is unique to the current model (perhaps some kind of aggregation of certain columns in the sharedByAllModels dataframe).

bokov
  • 3,444
  • 2
  • 31
  • 49

2 Answers2

3

Answering your main question, you can use bquote() to control which parts of the updating formula object (namely those within .()) get evaluated.

mylist <- list(y ~ a + b, y ~ A + B)
myotherlist <- list("c", "C")

lapply(1:2, function(ii) {
    jj <- as.name(myotherlist[[ii]])
    update(mylist[[ii]], bquote(. ~ . + .(jj)))})
# [[1]]
# y ~ a + b + c
# 
# [[2]]
# y ~ A + B + C

Alternatively, use substitute() in a similar fashion:

lapply(1:2, function(ii) {
      jj <- as.name(myotherlist[[ii]])
      update(mylist[[ii]], substitute(. ~ . + jj))
      })
# [[1]]
# y ~ a + b + c
# 
# [[2]]
# y ~ A + B + C
Josh O'Brien
  • 159,210
  • 26
  • 366
  • 455
1

Use do.call, which evaluates its arguments before execution. See anova test fails on lme fits created with pasted formula.

Community
  • 1
  • 1
Aaron left Stack Overflow
  • 36,704
  • 7
  • 77
  • 142