Skip to content

Help using mapply to run multiple models

11 messages · Simon Kiss, Bert Gunter, David Winsemius +1 more

#
Dennis, how would your function be modified to allow it to be more flexible in future. 
I'm thinking like:
I tried that then using 
modlist <- lapply(xvars, f), but it didn't work.
On 2013-12-18, at 3:29 AM, Dennis Murphy <djmuser at gmail.com> wrote:

            
*********************************
Simon J. Kiss, PhD
Assistant Professor, Wilfrid Laurier University
73 George Street
Brantford, Ontario, Canada
N3T 2C9
Cell: +1 905 746 7606
#
Folks:

1. Haven't closely followed the thread. I'm responding only to Simon's post.

2. ?formula ## Especially note the use of "."

So just make an appropriately constructed data frame for the data
argument of glm:

## example
## y does not need to be in the data frame.

Another way to handle the OP is via substitute() or bquote(). I'll
leave that to thers to explain.

-- Bert
On Wed, Dec 18, 2013 at 9:11 AM, Simon Kiss <sjkiss at gmail.com> wrote:

  
    
#
Try something like the following.  Because lm() evaluates many
of its arguments in nonstandard ways, f() manipulates the call
and then evaluates it in the frame from which f() was called.
It also puts that environment on the formula that it creates so
it can refer to variables in that environment.
    f <- function (responseName, predictorNames, data, ..., envir = parent.frame())
    {
        call <- match.call()
        call$formula <- formula(envir = envir, paste(responseName, sep = " ~ ",
            paste0("`", predictorNames, "`", collapse = " + ")))
                call[[1]] <- quote(glm) # 'f' -> 'glm'
        call$responseName <- NULL # omit responseName=
        call$predictorNames <- NULL # omit 'predictorNames='
                eval(call, envir = envir)
    }
as in
    z <- lapply(list(c("hp","drat"), c("cyl"), c("am","gear")), FUN=function(preds)f("carb", preds, data=mtcars, family=poisson))
    lapply(z, summary)

Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com
#
Hello Bill, that is fantastic and it's quite a bit above what I could write. Is there a way to make the model type an argument to the function so that you can specify whether one is running glm, lm and such? 
I tried to modify it by inserting an argument modelType below, but that doesn't work.
Yours, simon Kiss
On 2013-12-18, at 3:07 PM, William Dunlap <wdunlap at tibco.com> wrote:

            
*********************************
Simon J. Kiss, PhD
Assistant Professor, Wilfrid Laurier University
73 George Street
Brantford, Ontario, Canada
N3T 2C9
Cell: +1 905 746 7606
#
makes call[[1]] the same as as.name("modelType").  You want
as.name(modelType).

Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com
#
On Dec 19, 2013, at 11:10 AM, William Dunlap wrote:

            
Just so I can see if I understand ... that is because `as.name` will evaluate `modelType` whereas as.name("modelType") would look for the function `modelType` and not find such a name in the namespace? So modelType needs to be a language-object and `f` needs to be called with:

f(glm, ....) rather than f("glm", ...)
David Winsemius
Alameda, CA, USA
#
On Dec 19, 2013, at 11:30 AM, David Winsemius wrote:

            
Reading `?as.name` (again) I've decided that must be wrong. either one should return the same value if teh argument is first converted to a character value.
#
Almost.  as.name(modelType) will evaluate modelType so modelType could be a
character string or a name.   as.name itself does not do any lookups - that is eval's job.
When eval() is given a name object it looks it up.
If you use as.name(modelType) then you could call f("glm",...).

f(glm, ...) does not pass a name into the function f, it passes in the object
named "glm" (usually the function in package:stats by that name).
as.name(glm) returns garbage.  If you wanted to be able to call
   f(glm, predictors, response)
you could just use
   call[[1]] <- modelType
in f().  I didn't recommend that because then the call attributes of glm's output
does not look nice.  You can write code so that both f("glm",...) and f(glm,...) work
but I usually prefer not to load up functions with so much heuristic argument
processing (e.g., how should it deal with 'func<-"glm" ; f(func,...)' and the like).

Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com
#
On Dec 19, 2013, at 11:45 AM, William Dunlap wrote:

            
So by the time the function `f` "saw" its arguments from a call:  `f(glm, ...) `, the name of the function would already have been removed and you would just be getting the argument list attached to the function body and as.name() would make a hash of it .... as we saw in the original portion of this question.
David Winsemius
Alameda, CA, USA
#
Hi there: Just to tie this altogether.

Here is the final function

f<- function (modelType, responseName, predictorNames, data, ..., envir = parent.frame())
{
  call <- match.call()
  call$formula <- formula(envir = envir, paste(responseName, sep = " ~ ",
                                               paste0("`", predictorNames, "`", collapse = " + ")))
  call[[1]] <- as.name(modelType)
  call$responseName <- NULL # omit responseName=
  call$predictorNames <- NULL # omit 'predictorNames='
  eval(call, envir = envir)
}
  
Here I call the function to a list of predictor variables and one dependent variable. Note "glm" and not glm.
z <- lapply(list(c("hp","drat"), c("cyl"), c("am","gear")), FUN=function(preds)f("glm", "carb", preds, data=mtcars, family='binomial'))

I do get this error:
Error in glm.control(modelType = "glm") : 
  unused argument(s) (modelType = "glm")

But 
lapply(z, summary)

does seem to return a list of model summaries. It looks like it worked.

I also tried. 
z <- lapply(list(c("hp","drat"), c("cyl"), c("am","gear")), FUN=function(preds)f("lm", "mpg", preds, data=mtcars))

Here, I get:
1: In lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) :
  extra argument ?modelType? is disregarded.
2: In lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) :
  extra argument ?modelType? is disregarded.
3: In lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) :
  extra argument ?modelType? is disregarded.

But again, it actually looks like it worked.
So, thank you very much!
Yours, Simon Kiss
On 2013-12-19, at 1:55 PM, Simon Kiss <sjkiss at gmail.com> wrote:

            
*********************************
Simon J. Kiss, PhD
Assistant Professor, Wilfrid Laurier University
73 George Street
Brantford, Ontario, Canada
N3T 2C9
Cell: +1 905 746 7606
#
Add the line
   call$modelType <- NULL # omit modelType argument
to your function.  Otherwise
   f("glm", ...)
makes the call
   glm(modelType="glm", ...)
where you want it to make the call
   glm(...)

Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com