4

How can I dynamically update a formula?

Example:

myvar <- "x"

update(y ~ 1 + x, ~ . -x)
# y ~ 1 (works as intended)

update(y ~ 1 + x, ~ . -myvar)
# y ~ x (doesn't work as intended)

update(y ~ 1 + x, ~ . -eval(myvar))
# y ~ x (doesn't work as intended)
mat
  • 2,412
  • 5
  • 31
  • 69

1 Answers1

4

You can use paste() within the update()call.

myvar <- "x"
update(y ~ 1 + x, paste(" ~ . -", myvar))
# y ~ 1

Edit

As @A.Fischer noted in the comments, this won't work if myvar is a vector of length > 1

myvar <- c("k", "l")
update(y ~ 1 + k + l + m, paste(" ~ . -", myvar))
# y ~ l + m
# Warning message:
# Using formula(x) is deprecated when x is a character vector of length > 1.
#   Consider formula(paste(x, collapse = " ")) instead.

Just "k" gets removed, but "l" remains in the formula.

In this case we could transform the formula into a strings, add/remove what we want to change and rebuild the formula using reformulate, something like:

FUN <- function(fo, x, negate=FALSE) {
  foc <- as.character(fo)
  s <- el(strsplit(foc[3], " + ", fixed=T))
  if (negate) {
    reformulate(s[!s %in% x], foc[2], env=.GlobalEnv)
  } else {
    reformulate(c(s, x), foc[2], env=.GlobalEnv)
  }
}

fo <- y ~ 1 + k + l + m

FUN(fo, c("n", "o"))  ## add variables
# y ~ 1 + k + l + m + n + o
FUN(fo, c("k", "l"), negate=TRUE))  ## remove variables
# y ~ 1 + m
jay.sf
  • 60,139
  • 8
  • 53
  • 110
  • 1
    Note that as of R 4.0, the above will return an error if "myvar" is a character vector. For possible workarounds, see here: https://stackoverflow.com/questions/65530492/dynamically-update-formula-with-vector-under-r-4-0-0-and-higher – A.Fischer Jan 01 '21 at 15:50
  • @A.Fischer What are you talking about? I tested the code in both R 4.0.3 and R 4.0.0 (out of curiosity) and it worked fine for me. – jay.sf Jan 02 '21 at 08:01
  • I am talking about a situation where myvar is a character vector and not a character scalar as above. If you e.g. have myvar <- c("x", "y") the above should fail under R 4.0 and higher. – A.Fischer Jan 02 '21 at 11:34
  • @A.Fischer Ah indeed, you meant a character vector of length > 1. Thanks! See edit. – jay.sf Jan 02 '21 at 15:54