Search code examples
rscoping

update function in R and variables access


I need to update a model formula inside a function. This is an example:

A <- runif(n = 200)             #  generate some data
B <- runif(n = 200)
P <- 1/(1+exp(.5-A))            #  generate event probability
outcome <- runif(n = 200) < P   #  generate outcome

my.function <- function(model, data.to.add) {   # this is the function for updating the formula
  new.model <- update(object = model, formula. = ~ . + data.to.add)
  return (new.model)
}

test <- my.function(model = glm(outcome ~ B, family = binomial(link="logit")), data.to.add = A) 

Unfortunately the execution of this code raises an error like this:

Error in eval(expr, envir, enclos) : object 'data.to.add' not found 

It seems that my.function cannot provide the value of variable data.to.add to update function. What can I do for giving the right scoping of variables to the update function inside another function?

Edit: Ok, your solution is good if the variables to be passed to the function to be updated are in the Global Environment, now if I have to define variables inside a function I get again an error due to less scoping of the variable:

A <- runif(n = 200)             #  generate some data
P <- 1/(1+exp(.5-A))            #  generate event probability
outcome <- runif(n = 200) < P   #  generate outcome

nested.update<-function(model) {
  B<-runif(n = 200)
  my.function <- function(model, data.to.add) {   # this is the function for updating the formula
    data.to.add <- paste('. ~ . +', deparse(substitute(data.to.add)), sep = "")
    new.model <- update(object = model, formula. = data.to.add)
    return (new.model)
  }
  return(my.function(model = model, data.to.add = B))
}

nested.update(model = glm(outcome ~ A, family = binomial(link="logit")))

Solution

  • edit

    my.function <- function(model, data.to.add) {   # this is the function for updating the formula
      data.to.add <- sprintf('. ~ . + %s', deparse(substitute(data.to.add)))
      new.model <- update(object = model, formula. = data.to.add)
      return (new.model)
    }
    
    my.function(lm(mpg ~ wt, data = mtcars), disp)
    
    # Call:
    #   lm(formula = mpg ~ wt + disp, data = mtcars)
    # 
    # Coefficients:
    #   (Intercept)           wt         disp  
    #      34.96055     -3.35083     -0.01772 
    
    my.function(lm(mpg ~ wt, data = mtcars), hp)
    
    # Call:
    #   lm(formula = mpg ~ wt + hp, data = mtcars)
    # 
    # Coefficients:
    #   (Intercept)           wt           hp  
    #      37.22727     -3.87783     -0.03177 
    

    bad answer:

    R is dispatching update.formula not the default update.default since you are passing a formula to update. The argument names are old and new. In update.default the names are model and formula. like you are using now.

    Also using a work around to get the correct variable name into the formula

    my.function <- function(model, data.to.add) {   # this is the function for updating the formula
      data.to.add <- sprintf('. ~ . + %s', deparse(substitute(data.to.add)))
      new.model <- update(old = model, new = data.to.add)
      return (new.model)
    }
    
    my.function(y ~ a, b)
    # y ~ a + b
    my.function(y ~ a, c)
    # y ~ a + c