7

I am trying to get used to scoping issues in R. I'd like to call the function glm() inside a function but it does not work, apparently for scoping reasons I did not manage to fix with the functions assign() or eval().

Here is a simplified version:

ao <- function (y, x, phi = seq (0,1,0.1), dataset, weights) {
    logLikvector <- rep(0,length(phi))  # vector of zeros to be replaced thereafter
    for (i in 1:length(phi)) {          # loop to use glm()   
        fit <- glm (y ~ x, data = dataset, family = binomial, weights = weights)         
        logLikvector[i] <- logLik(fit)      # get log likelihood
    }
    logLikvector
}

Now I want to use the function ao() on my dataset

    ao (y = Prop, x = Age, dataset = mydata, weights = Total) 

This does not work, but the following works:

ao (y = mydata$Prop, x = mydata$Age, dataset = mydata, weights = mydata$Total)

Does anyone know what to do ?

Any help would be greatly appreciated !!!

Btw, here is how to replicate my problem with the dataset I am using

library("MASS")
data(menarche)
mydata <- menarche
mydata$Prop <- mydata$Menarche / mydata$Total
IRTFM
  • 258,963
  • 21
  • 364
  • 487
user1431694
  • 715
  • 1
  • 11
  • 22

3 Answers3

6

Solution with substitute (@DWin suggestion).

function(y, x, dataset, weights){
  f <- substitute(glm(y~x, data=dataset, weights=weights, family=binomial))
  logLik(eval(f))
}
Wojciech Sobala
  • 7,431
  • 2
  • 21
  • 27
  • Many thanks Sobala ! I wouldn't have found it by myself easily as I am still at the beginning of the learning curve in R ! – user1431694 Jun 02 '12 at 21:34
3
ao <- function (x, y, phi = seq (0,1,0.1), dataset, weights) {
    logLikvector <- rep(0,length(phi))
    x <- dataset[,substitute(x)]
    y <- dataset[,substitute(y)]
    weights <- dataset[,substitute(weights)]
        for (i in 1:length(phi)) {          # loop to use glm()
        fit <- glm (y ~ x, data = dataset, family = binomial, weights = weights)
        logLikvector[i] <- logLik(fit)      # get log likelihood
    }
    return(logLikvector)
}



library("MASS")
data(menarche)
mydata <- menarche
mydata$Prop <- mydata$Menarche / mydata$Total
ao(y = "Prop",x = "Age", dataset = mydata, weights = "Total")


[1] -55.37763 -55.37763 -55.37763 -55.37763 -55.37763 -55.37763
 [7] -55.37763 -55.37763 -55.37763 -55.37763 -55.37763
Maiasaura
  • 32,226
  • 27
  • 104
  • 108
  • 1
    Instead of the slightly ugly `which(names(.)==arg` construction, why not use `substitute(arg)`? I tried it with your answer and it worked well in all three instances for your otherwise excellent answer. – IRTFM Jun 02 '12 at 01:55
  • Maiasaura, thank you ! This works indeed and I agree with DWin that using substitute (arg) is lighter. Anyway I understand better this scoping principle now... – user1431694 Jun 02 '12 at 21:31
  • @DWin: `substitute(arg)` is a really nice way of doing things like this within functions. Thanks for the tip! – Aaron left Stack Overflow Jun 03 '12 at 18:30
3

I suggest creating the formula with paste and calling the function with do.call.

ao <- function (y, x, phi = seq (0,1,0.1), dataset, weights) {
  logLikvector <- rep(0,length(phi))  # vector of zeros to be replaced thereafter
  for (i in 1:length(phi)) {          # loop to use glm()
    f <- as.formula(paste(y, x, sep="~"))
    fit <- do.call("glm", list(formula=f, data=as.name(dataset), 
                   family="binomial", weights=as.name(weights)))
    logLikvector[i] <- logLik(fit)      # get log likelihood
  }
  logLikvector
}

Then call it like this:

ao("Prop", "Age", dataset="mydata", weights="Total")

See https://stackoverflow.com/a/7668846/210673 for more details.

Community
  • 1
  • 1
Aaron left Stack Overflow
  • 36,704
  • 7
  • 77
  • 142
  • Aaron, thanks to you too ! Your answer allowed me to learn about do.call. I will use substitute(arg) as suggested by DWin. – user1431694 Jun 02 '12 at 21:33
  • In this case I might too, `substitute(arg)` is a great way to do this in this case. It actually does exactly the same thing as my solution except you can pass the parameters as names instead of characters (ie without quotes). – Aaron left Stack Overflow Jun 03 '12 at 18:34