Trouble passing on an argument to function within own function

不羁岁月 提交于 2019-11-27 14:33:02
Aaron

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)'

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)
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!