Проблема с передачей аргумента функции внутри собственной функции

Я пишу функцию, в которой хочу передать некоторые аргументы функции crrstep (пакет crrstep), но столкнулся с проблемой: почему-то аргумент «событие» в моей функции не распознается, когда я ввожу его в crrstep. Я предполагаю, что 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"

Большое спасибо! Роб


person Rob    schedule 18.02.2013    source источник
comment
Проблема в том, что вы rm(fstatus) перед тем, как передать его как event параметр вашей функции ...   -  person juba    schedule 18.02.2013
comment
Привет, джуба, прежде чем удалить fstatus, я добавил его в testdata, который затем использую в своей функции в качестве аргумента «данные». Я думал, что crrstep будет искать «событие» в «данных» (которые я также передаю crrstep), но почему-то это не так ...   -  person Rob    schedule 18.02.2013
comment
тогда вы должны использовать etype=data[,event] в своем crrstep() вызове и передать аргумент fstatus в виде строки: event="fstatus".   -  person juba    schedule 18.02.2013
comment
Когда я ввожу его так: test.fun <- function(x,data,event){ require(crrstep) select.mod<- crrstep(formula=x,,etype=data[,event], failcode=1, cencode=0,data=data, direction = "backward", criterion = "AIC", crr.object = TRUE, trace = TRUE) print(select.mod) } test.fun(x=formula1,data=testdata,event="fstatus") Я все равно получаю сообщение об ошибке: Ошибка в '[.data.frame' (данные,, событие): объект «событие» не найден   -  person Rob    schedule 18.02.2013
comment
Эти два недавних вопроса связаны между собой и также могут быть полезны: stackoverflow.com/q/14784302/210673 stackoverflow.com/q/14839689/210673   -  person Aaron left Stack Overflow    schedule 18.02.2013


Ответы (2)


При вызове функций внутри функций, которые зависят от оценки имен в пределах фрейма данных, я использую do.call, который оценивает свои аргументы перед передачей функции и, таким образом, упрощает отладку и написание кода, и я чувствую, что могу быть более уверен в том, что это делает. (Для отладки просто используйте call вместо do.call, который покажет, что функция будет пытаться запустить; синтаксис также немного отличается, поэтому при этом также удалите структуру списка внутри вызова.)

(Благодарим Джоша О'Брайена за эту идею: 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) 

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)

Естественный способ, который не работает, потому что он ищет 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

Вызов можно построить со строками; это немного проще:

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

Или можно использовать 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)

Но я мог бы также использовать 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)

Он также работает, чтобы вставить фактический фрейм данных, но вызов длиннее. Однако это может быть желательно, если вы изменяете фрейм данных программно перед каждым вызовом и хотите иметь запись о том, что это за фрейм данных. (Однако я бы предпочел сохранить этот фрейм данных более явным образом, если он вам действительно понадобится позже.)

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

Еще одно, чтобы показать, что вы не можете просто использовать 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)'
person Aaron left Stack Overflow    schedule 18.02.2013
comment
Привет, Аарон, спасибо за четкое объяснение, это решение отлично работает для меня! - person Rob; 18.02.2013
comment
@aaron Это очень интересно, большое спасибо за подробное объяснение. Но теперь у меня разболелась голова :) - person juba; 18.02.2013

Я не совсем понимаю, почему, но, похоже, он потерпит неудачу, если вы передадите свой аргумент etype в качестве индексированного фрейма данных. Однако, похоже, это сработает, если вы заранее создадите вектор:

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)
}
person juba    schedule 18.02.2013
comment
Интересно, что у меня это, похоже, не сработало; Я все еще получаю сообщение Error in '[.data.frame'(data, , event) : object 'event' not found. - person Aaron left Stack Overflow; 18.02.2013