Search code examples
rnamespacesglmmgcvdo.call

do.call fails for mgcv::gam as string, but not other functions


I am trying to fit several different models using a master function as the workhorse (each function calls this master function with the variable model as a string and the required parameters passed via ...)

It works fine for model = "loess" and model = "glm", but fails for model = "gam". Specifically, do.call(model, args) will fail unless I hardcode the function name with the namespace. But I need model to be a variable. The same problem occurs for formalArgs which I use to get args. E.g (reprex) based on suggestions from similar SO questions:

model <- "mgcv::gam"
formalArgs(mgcv::gam)                   # Works but function is hard-coded
formalArgs(gam)                         # Fails
formalArgs(model)                       # Fails
formalArgs(eval(model))                 # Fails
formalArgs(substitute(model))           # Returns NULL with warning
formalArgs(deparse(substitute(model)))  # Fails

The error message is Error in get(fun, mode = "function", envir = envir) : object '"mgcv::gam"' of mode 'function' was not found (or in the case of substitute, returns NULL).

If model is changed to "glm" or "loess", then formalArgs(model) and formalArgs(eval(model)) work.

I think this has something to do with these two functions both being from the base stats package while gam is not. But how do I solve it?


Solution

  • The problem is that "mgcv::gam" is text for an expression, not the name of a function. The function name is "gam".

    To retrieve the formals, you can use formalArgs(x) where x is the name of a function that's available on the search list, or an actual function object.

    That's why formalArgs(mgcv::gam) works, because that expression retrieves the function object. Other ways to do it would be

        model <- mgcv::gam
        formalArgs(model)
    #>  [1] "formula"            "family"             "data"              
    #>  [4] "weights"            "subset"             "na.action"         
    #>  [7] "offset"             "method"             "optimizer"         
    #> [10] "control"            "scale"              "select"            
    #> [13] "knots"              "sp"                 "min.sp"            
    #> [16] "H"                  "gamma"              "fit"               
    #> [19] "paraPen"            "G"                  "in.out"            
    #> [22] "drop.unused.levels" "drop.intercept"     "nei"               
    #> [25] "discrete"           "..."
        model <- "mgcv::gam"
        obj <- eval(parse(text = model))
        formalArgs(obj)
    #>  [1] "formula"            "family"             "data"              
    #>  [4] "weights"            "subset"             "na.action"         
    #>  [7] "offset"             "method"             "optimizer"         
    #> [10] "control"            "scale"              "select"            
    #> [13] "knots"              "sp"                 "min.sp"            
    #> [16] "H"                  "gamma"              "fit"               
    #> [19] "paraPen"            "G"                  "in.out"            
    #> [22] "drop.unused.levels" "drop.intercept"     "nei"               
    #> [25] "discrete"           "..."
    

    Created on 2023-10-03 with reprex v2.0.2

    Edited to add: as the comments to your question said, using formalArgs("gam") would also work, but only if mgcv was on the search list (because you had run library(mgcv) to put it there, or some equivalent).