Trouble passing on an argument to function within own function

前端 未结 2 1143
粉色の甜心
粉色の甜心 2020-12-03 13:00

I am writing a function in which I want to pass some arguments to the crrstep-function (\'crrstep\' package), but I encountered a problem: somehow the argument \'event\' in

相关标签:
2条回答
  • 2020-12-03 13:52

    I don't clearly understand why, but it seems to fail if you pass your etype argument as an indexed data frame. However it seems to work if you create the vector beforehand :

    test.fun <- function(x,data,event){
      require(crrstep)
      etype <- data[,event]
      select.mod<- crrstep(formula=x,data=data,etype=etype, failcode=1, cencode=0, 
                       direction = "backward", criterion = "AIC", crr.object = TRUE, 
                       trace = FALSE)
    #Rest of function omitted for now
    print(select.mod)
    }
    
    0 讨论(0)
  • 2020-12-03 13:53

    When calling functions within functions that depend on evaluating names within a data frame, I use do.call, which evaluates its arguments before passing to the function and so makes both debugging and writing the code simpler, and I feel like I can be more sure about what it's doing. (For debugging, just use call instead of do.call, which will show what the function will try to run; the syntax is also a little different so when doing this remove the list structure within the call as well.)

    (Credit to Josh O'Brien's answer here for this idea: https://stackoverflow.com/a/7668846/210673)

    In this case, it would look like this:

    test.fun <- function(x, data, event){
      require(crrstep)
      select.mod <- do.call("crrstep", 
             list(formula=x, etype=substitute(event), failcode=1, cencode=0,
                  data=as.name("data"), direction = "backward", criterion = "AIC", 
                  crr.object = TRUE, trace = FALSE))
      print(select.mod)
    }
    
    test.fun(x=formula1, data=testdata, event=fstatus) 
    

    The substitute(event) tells it to use the name that was given to the function, not the name event. The as.name("data") tells it to look for data within the function instead of passing the actual data frame. Another option is substitute(data) which will look for the actual data frame you have.

    an example using lm

    Here's an example of very similar behavior using lm and the weights argument:

    Here's an example data set and the call to lm, not within another function. I print the call element of the response to see what it actually did.

    > set.seed(5)
    > dd <- data.frame(x=1:10,y=round(rnorm(10,mean=10),1), z=round(runif(10,1,4),1))
    > lm(y~x, weights=z, data=dd)$call
    lm(formula = y ~ x, data = dd, weights = z)
    

    The natural way, which doesn't work because it's looking for w in the data frame:

    > f1 <- function(f,w,d){
    +   lm(formula=f,weights=w, data=d)
    + }
    > f1(y~x, z, dd)
    Error in eval(expr, envir, enclos) : object 'w' not found
    

    One can build the call with strings; this is a little more straightforward:

    > f2 <- function(f,w,d){
    +   do.call("lm", list(formula=as.formula(f), weights=as.name(w), data=as.name(d)))
    + }
    > f2("y~x", "z", "dd")$call
    lm(formula = y ~ x, data = dd, weights = z)
    

    Or one can use substitute; here I'm calling the function on my actual data set dd, not the d within the function. This might be useful later if I want to use update.

    > f3 <- function(f,w,d){
    +   do.call("lm", list(formula=f, weights=substitute(w), data=substitute(d)))
    + }
    > f3(y~x, z, dd)$call
    lm(formula = y ~ x, data = dd, weights = z)
    

    But I could also use d within the function; this time notice that data = d in the call instead of data = dd.

    > f4 <- function(f,w,d){
    +   do.call("lm", list(formula=f, weights=substitute(w), data=as.name("d")))
    + }
    > f4(y~x, z, dd)$call
    lm(formula = y ~ x, data = d, weights = z)
    

    It works to put in the actual data frame as well, but the call is longer. This however, might be desired if you're changing the data frame programatically before each call and want to have a record of what that data frame is. (My preference, though, would be to save that data frame in a more explicit way, if you really do want it later.)

    > f5 <- function(f,w,d){
    +   do.call("lm", list(formula=f, weights=substitute(w), data=d))
    + }
    > f5(y~x, z, dd)$call
    lm(formula = y ~ x, data = list(x = 1:10, y = c(9.2, 11.4, 8.7, 
    10.1, 11.7, 9.4, 9.5, 9.4, 9.7, 10.1), z = c(3.7, 3.2, 1.6, 1.7, 
    1.4, 2.4, 2.3, 3.9, 1.4, 3.9)), weights = z)
    

    One more to show that you can't just use substitute without do.call as the substitute is executed within the call to lm.

    > f6 <- function(f,w,d){
    +   lm(formula=f,weights=substitute(w), data=d)
    + }
    > f6(y~x, z, dd)
    Error in model.frame.default(formula = f, data = d, weights = substitute(w),  : 
      invalid type (symbol) for variable '(weights)'
    
    0 讨论(0)
提交回复
热议问题