predict.lme 无法解释由变量定义的公式

huangapple go评论94阅读模式
英文:

predict.lme is unable to interpret a formula defined from a variable

问题

我一直受到一个错误的困扰,这个错误追溯到在一个函数内部运行的predict.lme,它无法解释基于从函数外部传递的变量的公式。我知道这个问题与变量作用域和不同的环境有关,但我一直无法完全理解它或找到一种解决方法。您的帮助将不胜感激。

以下是一个可重现的示例:

  1. # 这将是嵌套函数。
  2. train_test_perf <- function(train_data, test_data, model, termLabels) {
  3. fixForm <- reformulate(termlabels=termLabels, response="Y")
  4. fit <- nlme::lme(fixForm, data=train_data, random=~ 1|ID)
  5. train_pred <- predict(fit, newdata=train_data, level=0, na.action=na.exclude)
  6. rtrain <- cor.test(train_data$Y, train_pred)
  7. test_pred <- predict(fit, newdata=test_data, level=0, na.action=na.exclude)
  8. rtest <- cor.test(test_data$Y, test_pred)
  9. tmp <- data.frame(Model=model,
  10. R_train=rtrain$estimate,
  11. R_test=rtest$estimate)
  12. return(tmp)
  13. }
  14. # 这是调用它的函数。
  15. myfunc <- function(df, newdf, varList) {
  16. for (v in varList) {
  17. perf <- train_test_perf(train_data=df, test_data=newdf, model=v, termLabels=v)
  18. print(perf)
  19. }
  20. }
  21. # 外部函数调用。
  22. myfunc(df=dat, newdf=newdat, varList=list("W", "X"))

运行这个代码会产生以下错误和回溯:

  1. Error in eval(mCall$fixed) : object 'fixForm' not found
  2. 7.
  3. eval(mCall$fixed)
  4. 6.
  5. eval(mCall$fixed)
  6. 5.
  7. eval(eval(mCall$fixed)[-2])
  8. 4.
  9. predict.lme(fit, newdata = train_data, level = 0, na.action = na.exclude)
  10. 3.
  11. predict(fit, newdata = train_data, level = 0, na.action = na.exclude)
  12. 2.
  13. train_test_perf(train_data = df, test_data = newdf, model = v,
  14. termLabels = v)
  15. 1.
  16. myfunc(df = dat, newdf = newdat, varList = list("W", "X"))

似乎predict.lme无法访问fixForm变量,但我一直无法找到一种既能定义基于变量的公式又能让predict.lme访问值的方法。我不确定嵌套函数结构是否是这里的问题的一部分 - 如果是的话,我希望找到一种维护这种结构的解决方法,因为我的真实代码包括在myfunc之前和之后发生的一些其他事情。

谢谢,Jeff Phillips

英文:

I have been stymied by an error that traces back to predict.lme, running inside a function, failing to interpret a formula based on a variable that has been passed from outside the function. I know the issue has to do with variable scope and different environments, but I've been unable to fully understand it or find a workaround. Your help would be much appreciated.

Here's a reproducible example:

  1. # This will be the nested function.
  2. train_test_perf &lt;- function(train_data, test_data, model, termLabels) {
  3. fixForm &lt;- reformulate(termlabels=termLabels, response=&quot;Y&quot;)
  4. fit &lt;- nlme::lme(fixForm, data=train_data, random=~ 1|ID)
  5. train_pred &lt;- predict(fit, newdata=train_data, level=0, na.action=na.exclude)
  6. rtrain &lt;- cor.test(train_data$Y, train_pred)
  7. test_pred &lt;- predict(fit, newdata=test_data, level=0, na.action=na.exclude)
  8. rtest &lt;- cor.test(test_data$Y, test_pred)
  9. tmp &lt;- data.frame(Model=model,
  10. R_train=rtrain$estimate,
  11. R_test=rtest$estimate)
  12. return(tmp)
  13. }
  14. # And here is the function that calls it.
  15. myfunc &lt;- function(df, newdf, varList) {
  16. for (v in varList) {
  17. perf &lt;- train_test_perf(train_data=df, test_data=newdf, model=v, termLabels=v)
  18. print(perf)
  19. }
  20. }
  21. # The outer function call.
  22. myfunc(df=dat, newdf=newdat, varList=list(&quot;W&quot;, &quot;X&quot;))

Running this gives the following error and traceback:

  1. Error in eval(mCall$fixed) : object &#39;fixForm&#39; not found
  2. 7.
  3. eval(mCall$fixed)
  4. 6.
  5. eval(mCall$fixed)
  6. 5.
  7. eval(eval(mCall$fixed)[-2])
  8. 4.
  9. predict.lme(fit, newdata = train_data, level = 0, na.action = na.exclude)
  10. 3.
  11. predict(fit, newdata = train_data, level = 0, na.action = na.exclude)
  12. 2.
  13. train_test_perf(train_data = df, test_data = newdf, model = v,
  14. termLabels = v)
  15. 1.
  16. myfunc(df = dat, newdf = newdat, varList = list(&quot;W&quot;, &quot;X&quot;))

It seems clear that predict.lme does not have access to the fixForm variable, but I haven't been able to work out a way to both define a formula based on a variable and have the value accessible to predict.lme. I'm not sure whether the nested function structure is part of the problem here--if it is, I would prefer to find a workaround that would maintain this structure, as my real-life code includes some other things inside myfunc that occur before and after the call to train_test_perf.

Thanks,

Jeff Phillips

答案1

得分: 1

使用变量作为公式不会存储变量,而是存储可能存在的问题的公式。我们可以使用 do.call

  1. train_test_perf <- function(train_data, test_data, model, termLabels) {
  2. fixForm <- reformulate(termlabels=termLabels, response="Y")
  3. fit <- do.call(nlme::lme, list(fixForm, data=quote(train_data), random=~ 1|ID))
  4. train_pred <- predict(fit, newdata=train_data, level=0, na.action=na.exclude)
  5. rtrain <- cor.test(train_data$Y, train_pred)
  6. test_pred <- predict(fit, newdata=test_data, level=0, na.action=na.exclude)
  7. rtest <- cor.test(test_data$Y, test_pred)
  8. tmp <- data.frame(Model=model, R_train=rtrain$estimate,
  9. R_test=rtest$estimate)
  10. return(tmp)
  11. }

最后,将它放在 sapply 中以避免繁琐的 for 循环。

  1. t(sapply(c("W", "X"), \(x) train_test_perf(train_data=dat, test_data=newdat, model=x, termLabels=x)))
  2. # Model R_train R_test
  3. # [1,] "W" 0.1686495 -0.001738604
  4. # [2,] "X" 0.4138526 0.2992374
英文:

Using a variable as formula doesn't stores the variable not the formula which might be the issue. We can use a do.call.

  1. train_test_perf &lt;- function(train_data, test_data, model, termLabels) {
  2. fixForm &lt;- reformulate(termlabels=termLabels, response=&quot;Y&quot;)
  3. fit &lt;- do.call(nlme::lme, list(fixForm, data=quote(train_data), random=~ 1|ID))
  4. train_pred &lt;- predict(fit, newdata=train_data, level=0, na.action=na.exclude)
  5. rtrain &lt;- cor.test(train_data$Y, train_pred)
  6. test_pred &lt;- predict(fit, newdata=test_data, level=0, na.action=na.exclude)
  7. rtest &lt;- cor.test(test_data$Y, test_pred)
  8. tmp &lt;- data.frame(Model=model, R_train=rtrain$estimate,
  9. R_test=rtest$estimate)
  10. return(tmp)
  11. }

Finally put it in an sapply to avoid tedious for loops.

  1. t(sapply(c(&quot;W&quot;, &quot;X&quot;), \(x) train_test_perf(train_data=dat, test_data=newdat, model=x, termLabels=x)))
  2. # Model R_train R_test
  3. # [1,] &quot;W&quot; 0.1686495 -0.001738604
  4. # [2,] &quot;X&quot; 0.4138526 0.2992374

huangapple
  • 本文由 发表于 2023年2月19日 01:58:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/75495308.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定