lme模型的用户定义函数适用:错误。

时间:2022-11-05 12:06:30

I am beginning to write a function that builds linear mixed models with nlme. I am encountering an error: Error in eval(expr, envir, enclos) : object 'value' not found, which I believe is due to R not knowing where to find the data frame variables (e.g., value). If this is, in fact, why the error is occurring, how do I tell the function that value and timepoint belong to the variables in Dat in the (reproducible) code below?

我开始写一个函数,用nlme建立线性混合模型。我遇到了一个错误:eval(expr, envir, enclos)中的错误:没有找到对象'value',我认为这是由于R不知道在哪里找到数据框架变量(例如,value)。如果这是错误发生的原因,那么如何告诉函数值和时间点属于下面(可重复的)代码中的Dat中的变量?

require(nlme)
Dat <- data.frame(
    id = sample(10:19),
    Time = sample(c("one", "two"), 10, replace = T),
    Value = sample(1:10)
)
nlme_rct_lmm <- function (data, value, timepoint,
                      ID) {

    #base_level intercept only model
    bl_int_only <- gls(value ~ 1, 
                       data = data, 
                       method = "ML", 
                       na.action="na.omit")        
    #vary intercept across participants
    randomIntercept <- lme(value ~ 1, 
                           data = data, 
                           random = ~1|ID, 
                           method = "ML", 
                           na.action = "na.omit")       
    #add timepoint as a fixed effect
    timeFE <- lme(value ~ timepoint, 
                  data = data, 
                  random = ~1|ID, 
                  method = "ML", 
                  na.action = "na.omit")
}
nlme_rct_lmm(Dat, Value, Time, id)

1 个解决方案

#1


3  

This isn't (as you and I both expected) a problem with evaluation within different frames; rather, it's an issue of consistency between the names of the variables between the formula and the data. R is case-sensitive, so it matters whether you use value or Value, id or ID, etc.. Furthermore, formula interpretation uses non-standard evaluation (NSE), so if you have a variable value equal to the symbol Value, value ~ 1 does not magically get transmuted to Value ~ 1. What I've outlined below works by passing the names of the response, time, and ID variables to the function, because it's the easiest approach. It's a little bit more elegant to the end-user if you use non-standard evaluation, but that's a bit harder to program (and therefore understand, debug, etc.).

这不是(正如你我都预料的)不同框架下的评估问题;而是公式和数据之间变量名的一致性问题。R是区分大小写的,所以使用值或值、id或id等都很重要。此外,公式解释使用非标准求值(NSE),因此,如果有一个变量值等于符号值,那么值~ 1不会神奇地转化为值~ 1。我在下面概述的工作是通过将响应、时间和ID变量的名称传递给函数,因为这是最简单的方法。如果您使用非标准的评估,那么对最终用户来说会更加优雅一些,但是这有点难于编写程序(因此理解、调试等等)。

Below the easy/boneheaded approach, I also discuss how to implement the NSE approach (scroll all the way down ...)

在简单/愚蠢的方法下面,我还讨论了如何实现NSE方法(向下滚动……)

Note that your example doesn't return anything; with R, that means that all the results will be discarded when it finishes the function. You might want to return the results as a list (or perhaps your real function will do something other stuff with the fitted models, such as a series of model tests, and return those answers as the results ...)

注意,您的示例没有返回任何内容;对于R,这意味着当它完成函数时,所有的结果都将被丢弃。您可能希望以列表的形式返回结果(或者您的真实函数将对已拟合模型做一些其他事情,例如一系列模型测试,并将这些答案作为结果返回…)

require(nlme)

Dat <- data.frame(
    ID = sample(10:19),
    Time = sample(c("one", "two"), 10, replace = T),
    Value = sample(1:10)
)

nlme_rct_lmm <- function (data, value, timepoint,
                      ID) {

    nullmodel <- reformulate("1",response=value)
    fullmodel <- reformulate(c("1",timepoint),response=value)
    remodel <- reformulate(paste("1",ID,sep="|"))

    #base_level intercept only model
    bl_int_only <- gls(nullmodel,
                       data = data, 
                       method = "ML", 
                       na.action="na.omit")

    #vary intercept across participants
    randomIntercept <- lme(nullmodel,
                           data = data, 
                           random = remodel,
                           method = "ML", 
                           na.action = "na.omit")

    #add timepoint as a fixed effect
    timeFE <- lme(fullmodel,
                  data = data, 
                  random = remodel,
                  method = "ML", 
                  na.action = "na.omit")
}

nlme_rct_lmm(Dat, "Value", "Time", "ID")

If you want something a bit more elegant (but internally obscure) you can substitute the following lines for defining the models. The inner substitute() calls retrieves the symbols that were passed to the function as arguments; the outer substitute() calls insert those symbols into the formula.

如果您想要一些更优雅(但内部不清楚)的东西,您可以用以下几行来定义模型。内部的substitute()调用检索作为参数传递给函数的符号;外部的substitute()调用将这些符号插入到公式中。

nullmodel <- formula(substitute(v~1,list(v=substitute(value))))
fullmodel <- formula(substitute(v~t,list(v=substitute(value),
                                 t=substitute(timepoint))))
remodel <- formula(substitute(~1|i,list(i=substitute(ID))))

Now this would work, without specifying the variables as strings, as you expected: nlme_rct_lmm(Dat, Value, Time, ID)

现在,这就可以工作了,无需像您期望的那样将变量指定为string: nlme_rct_lmm(Dat, Value, Time, ID)

#1


3  

This isn't (as you and I both expected) a problem with evaluation within different frames; rather, it's an issue of consistency between the names of the variables between the formula and the data. R is case-sensitive, so it matters whether you use value or Value, id or ID, etc.. Furthermore, formula interpretation uses non-standard evaluation (NSE), so if you have a variable value equal to the symbol Value, value ~ 1 does not magically get transmuted to Value ~ 1. What I've outlined below works by passing the names of the response, time, and ID variables to the function, because it's the easiest approach. It's a little bit more elegant to the end-user if you use non-standard evaluation, but that's a bit harder to program (and therefore understand, debug, etc.).

这不是(正如你我都预料的)不同框架下的评估问题;而是公式和数据之间变量名的一致性问题。R是区分大小写的,所以使用值或值、id或id等都很重要。此外,公式解释使用非标准求值(NSE),因此,如果有一个变量值等于符号值,那么值~ 1不会神奇地转化为值~ 1。我在下面概述的工作是通过将响应、时间和ID变量的名称传递给函数,因为这是最简单的方法。如果您使用非标准的评估,那么对最终用户来说会更加优雅一些,但是这有点难于编写程序(因此理解、调试等等)。

Below the easy/boneheaded approach, I also discuss how to implement the NSE approach (scroll all the way down ...)

在简单/愚蠢的方法下面,我还讨论了如何实现NSE方法(向下滚动……)

Note that your example doesn't return anything; with R, that means that all the results will be discarded when it finishes the function. You might want to return the results as a list (or perhaps your real function will do something other stuff with the fitted models, such as a series of model tests, and return those answers as the results ...)

注意,您的示例没有返回任何内容;对于R,这意味着当它完成函数时,所有的结果都将被丢弃。您可能希望以列表的形式返回结果(或者您的真实函数将对已拟合模型做一些其他事情,例如一系列模型测试,并将这些答案作为结果返回…)

require(nlme)

Dat <- data.frame(
    ID = sample(10:19),
    Time = sample(c("one", "two"), 10, replace = T),
    Value = sample(1:10)
)

nlme_rct_lmm <- function (data, value, timepoint,
                      ID) {

    nullmodel <- reformulate("1",response=value)
    fullmodel <- reformulate(c("1",timepoint),response=value)
    remodel <- reformulate(paste("1",ID,sep="|"))

    #base_level intercept only model
    bl_int_only <- gls(nullmodel,
                       data = data, 
                       method = "ML", 
                       na.action="na.omit")

    #vary intercept across participants
    randomIntercept <- lme(nullmodel,
                           data = data, 
                           random = remodel,
                           method = "ML", 
                           na.action = "na.omit")

    #add timepoint as a fixed effect
    timeFE <- lme(fullmodel,
                  data = data, 
                  random = remodel,
                  method = "ML", 
                  na.action = "na.omit")
}

nlme_rct_lmm(Dat, "Value", "Time", "ID")

If you want something a bit more elegant (but internally obscure) you can substitute the following lines for defining the models. The inner substitute() calls retrieves the symbols that were passed to the function as arguments; the outer substitute() calls insert those symbols into the formula.

如果您想要一些更优雅(但内部不清楚)的东西,您可以用以下几行来定义模型。内部的substitute()调用检索作为参数传递给函数的符号;外部的substitute()调用将这些符号插入到公式中。

nullmodel <- formula(substitute(v~1,list(v=substitute(value))))
fullmodel <- formula(substitute(v~t,list(v=substitute(value),
                                 t=substitute(timepoint))))
remodel <- formula(substitute(~1|i,list(i=substitute(ID))))

Now this would work, without specifying the variables as strings, as you expected: nlme_rct_lmm(Dat, Value, Time, ID)

现在,这就可以工作了,无需像您期望的那样将变量指定为string: nlme_rct_lmm(Dat, Value, Time, ID)