Friday 26 May 2017

class - How can you add (say a vectors name) to an object of type 'formula' within a function?



This is a very trimmed down version of what I want to do, I can't paste my exact problem cause the code is too long and complex but I think this gets at the root of issue. Thanks to Josh's answer to this question How do you code an R function so that it 'knows' to look in 'data' for the variables in other arguments? I'm part way there.




example <- function(model, xvar3=NULL, xvar4=NULL, data){
print(class(model))
#xvar3 <- eval(substitute(xvar3), envir=data, enclos=parent.frame())
#xvar4 <- eval(substitute(xvar4), envir=data, enclos=parent.frame())
print(class(xvar3))
xvar5 <- xvar4^2
mod <- glm( model + xvar3 + xvar5, data=data)
return(mod)
}


example(mpg ~ cyl, hp, wt, data=mtcars)


This fails. If you remove the comments (based on help from previous question) it solves the problem of 'finding' hp and wt. 'model' is of class formula and I would like that to become 'mpg ~ cyl + xvar3 + xvar5' so that the glm will run. But I can't seem to be able to add them to the formula.



I've been toying around with 'call' classes and further with 'eval', and 'as.formula' with variations of 'paste' and 'noquote' etc but can't see to get it to stick.


Answer



Here's one way. The trick I used is to create a new formula based on the given one + the two extra variables. I then did a trick with the environment of the formula so that both xvar3/xvar5 AND any variables local to the caller can be used.




glm will always look in the formula's environment AND in the data for variables (and nowhere else!). That's why the formula environment must the manipulated a bit in this case: it contains xvar3 and xvar5, and the parent environment is set to the original formula's environment so that it is also searched for variables (foo in the last example)...



example <- function(model, xvar3=NULL, xvar4=NULL, data){
e <- new.env(parent=environment(model))
e$xvar3 <- eval(substitute(xvar3), envir=data, enclos=parent.frame())
e$xvar4 <- eval(substitute(xvar4), envir=data, enclos=parent.frame())
e$xvar5 <- e$xvar4^2

model <- update(model, . ~ . + xvar3 + xvar5)
environment(model) <- e


mod <- glm(model, data=data)

return(mod)
}

example(mpg ~ cyl, hp, wt, data=mtcars)

# Using a local variable should work too:
doit <- function(d) {

foo <- d$cyl+1
example(mpg ~ foo, hp, wt, data=d)
}
doit(mtcars)

No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...