5

I would like to pass the right-hand side of a formula to an R function which then "adds" the left-hand side of the formula and calls gam(). I would like to achieve this without ugly as.formula() constructions etc.

I got stuck in the following minimal example, do you know what went wrong?

require(mgcv)
set.seed(0) ## set.seed(1)
gamEx1 <- gamSim(1, n=400, dist="normal", scale=2) ## simulate some data
str(gamEx1) ## display structure

## calling gam() and passing the right-hand side of a formula
gamFitter <- function(formula.RHS, data, ...){
    z <- 2*data$y + data$f0 # some given values
    gam(z ~ formula.RHS, data=data, ...) # call gam()
}

## call the function with the right-hand side of a formula
gamFitter(formula.RHS=~s(x0)+s(x1)+s(x2)+s(x3), data=gamEx1)

Error in model.frame.default(formula = z ~ formula.RHS, data = data,
                             drop.unused.levels = TRUE) :
  invalid type (language) for variable 'formula.RHS'
Paul Hiemstra
  • 59,984
  • 12
  • 142
  • 149
Marius Hofert
  • 6,546
  • 10
  • 48
  • 102

4 Answers4

12

It seems that you should use the built in functionality of R, namely update.formula, no need to write a new function:

> form <- ~s(x0)+s(x1)+s(x2)+s(x3)
> form
~s(x0)+s(x1)+s(x2)+s(x3)
> update.formula(form, z ~ .)
z ~ s(x0) + s(x1) + s(x2) + s(x3)
5

Here's a version building upon @gsk3's idea:

changeLHS <- function(formula, lhs) {
   if (length(formula) == 2) {
     formula[[3]] <- formula[[2]]
   }
   formula[[2]] <- substitute(lhs)
   formula
}

changeLHS(a~b+c, z+w)  # z + w ~ b + c
changeLHS(~b+c, z+w)   # z + w ~ b + c

So, your code becomes:

gamFitter <- function(formula.RHS, data, ...){
  frm <- changeLHS(formula.RHS, 2*y + f0)
  gam(frm, data=data, ...) # call gam()
}
Tommy
  • 39,997
  • 12
  • 90
  • 85
4

Kludgy but it works:

form1 <- as.formula("hi ~ lo + mid")
form2 <- as.formula("blue ~ red + green")
form2[[3]] <- form1[[3]]
> form2
blue ~ lo + mid
Ari B. Friedman
  • 71,271
  • 35
  • 175
  • 235
  • Well, as I wrote, I *don't* want to use `as.formula()` and strings, it's simply bad practice. Thanks anyway. – Marius Hofert Apr 14 '12 at 15:39
  • @MariusHofert - can you explain what is bad practice about `as.formula()`? – Chase Apr 14 '12 at 16:45
  • A formula is a formula -- and should be treated as such. Converting it to/treating it via strings is bad practice. Please note that the recommended approach to build functions with formulas is treated here: http://developer.r-project.org/model-fitting-functions.txt Two good examples which do *not* involve strings (and thus do not require `as.formula()`) are the functions `lm()` and `(mgcv::)gam`. – Marius Hofert Apr 14 '12 at 16:52
  • 4
    I only used as.formula in ehe examples. The mechanism of manipulating the formulas does not rely on it at all. – Ari B. Friedman Apr 14 '12 at 19:10
0

Building on the other answers, if you need to replace LHS programmatically by passing strings (à la reformulate), then two small tweaks can help.

Using @Tommy's approach:

changeLHS <- function(formula, lhs) {
    if (length(formula) == 2) {
        formula[[3]] <- formula[[2]]
    }
    formula[[2]] <- as.symbol(lhs)
    formula
}

form <- ~s(x0)+s(x1)+s(x2)+s(x3)
changeLHS(form, "z")
## z ~ s(x0) + s(x1) + s(x2) + s(x3)

Using @Derek's approach:

update(form, reformulate(".", "z"))
## z ~ s(x0) + s(x1) + s(x2) + s(x3)
Community
  • 1
  • 1
landroni
  • 2,902
  • 1
  • 32
  • 39