объект не найден в функции: nlmer edition

За последние несколько часов я нашел здесь несколько вопросов относительно сценария R, который отлично работает вне функции, но возвращает ошибку «объект не найден» для аргумента после того, как код реорганизован для включения функций. К сожалению, решение этих ошибок, по-видимому, в значительной степени зависит от пакета и контекста, поэтому я должен бросить в бой свою собственную проблему, специфичную для nlmer.

Подводя итог: я хотел бы запустить модель nlmer несколько раз, но каждый раз с немного другой спецификацией модели. Я убедился, что модель работает, как указано, вне каких-либо функций. Я написал функцию, которая принимает data.table и формулу (в строковой форме) и запускает модель, но она возвращает ошибку, что моя формула модели «не найдена», хотя переменная 'model_formula' определенно находится в пространство имен функции.

Пример:

# set up toy dataset
data <- data.table(patient_id=c(rep("pat_1", 10), rep("pat_2", 10), rep("pat_3", 10)),
                   agesero=c(rep(25,10), rep(19, 10), rep(34, 10)))
data$row <- as.numeric(rownames(data))
data[, variable:= ifelse(row%%10==0, "observed_survival", "vl")]
data[, M_visit_time:= ifelse(variable=="vl", row/6 + 0.25, 0)] 
data[, value:= ifelse(variable=="vl", 3 + exp(-4*M_visit_time), row/10 + 2)]
data[, M_agesero:= ifelse(variable=="vl", agesero, 0)]
data[, D_intercept:= ifelse(variable=="observed_survival", 1, 0)]
data[, D_agesero:= ifelse(variable=="observed_survival", agesero, 0)]
data[, row:=NULL]

example_formula <- "value~ModelGradient(time=M_visit_time,b0,b2,b3)~M_agesero + D_intercept + D_agesero + (b0|patient_id)"

#this works, outside of a function:
Model<- ~b0+b2*exp(-b3*time)
ModelGradient<-deriv(Model,namevec=c("b0","b2","b3"),
               function.arg=c("time","b0","b2","b3"))

out<-nlmer(as.formula(example_formula), data=data,
           start = c(b0=3,b2=1,b3=4),
           control=nlmerControl(optimizer="bobyqa", optCtrl=list(maxfun=200000)))

#but when I write a function:
run_nonlin<- function(model_formula, data){
            Model<- ~b0+b2*exp(-b3*time)
            ModelGradient<-deriv(Model,namevec=c("b0","b2","b3"),
                           function.arg=c("time","b0","b2","b3"))

          print(paste("hello I am the model formula and I exist in this namespace! I am:",
         model_formula))
         out<-nlmer(as.formula(model_formula), data=data,
                 start = c(b0=3,b2=1,b3=4),
                 control=nlmerControl(optimizer="bobyqa",
                  optCtrl=list(maxfun=200000)))
           return(out)
}

#and call:
function_output <- run_nonlin(model_formula=example_formula, data=data)

# I get the error: 
# Error in as.formula(model_formula) : object 'model_formula' not found

В качестве примечания, я сделал что-то очень похожее на это в glmer, без проблем.

Любые советы высоко ценится.

(отредактировано, чтобы включить сообщение об ошибке)


person abertozz    schedule 24.06.2015    source источник
comment
Конечно, извините за упущение. Я добавил текст ошибки внизу скрипта. Это: Ошибка в as.formula (model_formula): объект 'model_formula' не найден   -  person abertozz    schedule 25.06.2015
comment
Проблема в том, что as.formula по умолчанию работает в глобальной среде, где ModelGradient et al. не существует. Вам нужно будет поиграть с with и настройкой окружения. Это сложно, см. - stackoverflow.com/questions/8218196/   -  person jeremycg    schedule 25.06.2015


Ответы (1)


Кажется, что nlmer имеет странный способ синтаксического анализа формулы, которую вы передаете функции. Очевидно, вы не можете передать переменную, которая не определена в глобальной среде. Похоже, это связано с тем, что nlformula вызывает as.formula неоцененный символ, который передается как формула. Это означает, что для разрешения символов используется лексическая область видимости, поэтому поиск model_formula выполняется в пространстве имен stats, а затем в глобальной среде, а не в области, определенной вашей функцией.

Обходным решением было бы оценить этот параметр, а затем передать это значение через do.call(), например

run_nonlin<- function(model_formula, data){
    Model<- ~b0+b2*exp(-b3*time)
    ModelGradient<-deriv(Model,namevec=c("b0","b2","b3"),
                       function.arg=c("time","b0","b2","b3"))

    out <- do.call('nlmer', list(as.formula(model_formula), 
        data=quote(data),
        start = c(b0=3,b2=1,b3=4),
        control=nlmerControl(optimizer="bobyqa",
        optCtrl=list(maxfun=200000))))

    return(out)
}
person MrFlick    schedule 24.06.2015