Rob*_*ob 3 environment r function argument-passing
我正在编写一个函数,我想将一些参数传递给crrstep-function('crrstep'包),但我遇到了一个问题:当我在crrstep中输入时,我的函数中的参数'event'无法识别.我想crrstep看起来与我想要的环境不同,但即使经过几个小时的网络搜索解决方案,我似乎也无法弄清楚如何解决这个问题(我在编程方面经验不足......) .任何帮助将不胜感激!
这是一些模拟数据(来自crrstep文档的调整示例)和我的代码示例:
n <- 500
ftime <- rexp(n)
fstatus <- sample(0:2,n,replace=TRUE)
testdata <- matrix(runif(8*n),nrow=n)
testdata <- cbind(ftime,fstatus,testdata)
dimnames(testdata)[[2]] <- c('ftime','fstatus','x1','x2','x3','x4','x5','x6','x7','x8')
testdata <- as.data.frame(testdata)
formula1 <- ftime ~ 1 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8
rm(fstatus,ftime,n)
test.fun <- function(x,data,event){
require(crrstep)
select.mod<- crrstep(formula=x,,etype=event, failcode=1, cencode=0,data=data,
direction = "backward", criterion = "AIC", crr.object = TRUE,
trace = FALSE)
#Rest of function omitted for now
print(select.mod)
}
#Test
test.fun(x=formula1,data=testdata,event=fstatus)
#I get: Error in eval(expr, envir, enclos) : object 'event' not found"
Run Code Online (Sandbox Code Playgroud)
非常感谢!抢
在函数中调用函数时,依赖于在数据框中评估名称,我使用do.call它,在传递给函数之前评估它的参数,因此调试和编写代码更简单,我觉得我可以更确定它是什么这样做.(对于调试,只需使用call而不是do.call,它将显示函数将尝试运行的内容;语法也有所不同,因此在执行此操作时也会删除调用中的列表结构.)
(感谢Josh O'Brien在这里提出这个想法的答案:https://stackoverflow.com/a/7668846/210673)
在这种情况下,它看起来像这样:
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)
Run Code Online (Sandbox Code Playgroud)
该substitute(event)告诉它使用被赋予的功能,而不是名称的名称event.该as.name("data")告诉它来寻找data在函数中,而不是通过实际的数据帧.另一个选项是substitute(data)查找您拥有的实际数据框.
lm以下是使用lm和weights参数非常相似的行为示例:
这是一个示例数据集和调用lm,而不是在另一个函数内.我打印call响应的元素,看看它实际上做了什么.
> 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)
Run Code Online (Sandbox Code Playgroud)
自然的方式,因为它w在数据框中寻找而无效:
> 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
Run Code Online (Sandbox Code Playgroud)
可以使用字符串构建调用; 这有点简单:
> 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)
Run Code Online (Sandbox Code Playgroud)
或者可以使用substitute; 这里我在实际数据集上调用函数dd,而不是d函数内部.如果我想使用,这可能在以后有用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)
Run Code Online (Sandbox Code Playgroud)
但我也可以d在函数内使用; 这次注意data = d在通话中而不是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)
Run Code Online (Sandbox Code Playgroud)
它也可以放入实际的数据帧,但调用时间更长.但是,如果您在每次调用之前以编程方式更改数据框并希望记录该数据帧是什么,则可能需要这样做.(不过,我的偏好是以更明确的方式保存该数据框,如果你以后真的想要它.)
> 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)
Run Code Online (Sandbox Code Playgroud)
还有一个证明你不能只使用substitute不do.call作为substitute被调用内执行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)'
Run Code Online (Sandbox Code Playgroud)