【问题标题】:Calling update within a lapply within a function, why isn't it working?在函数内的 lapply 内调用更新,为什么它不起作用?
【发布时间】:2018-06-03 05:11:45
【问题描述】:

这是来自Error in calling `lm` in a `lapply` with `weights` argument 的后续问题,但可能不是同一个问题(但仍然相关)。

这是一个可重现的例子:

dd <- data.frame(y = rnorm(100),
                 x1 = rnorm(100),
                 x2 = rnorm(100),
                 x3 = rnorm(100),
                 x4 = rnorm(100),
                 wg = runif(100,1,100))

ls.form <- list(
  formula(y~x1+x2),
  formula(y~x3+x4),
  formula(y~x1|x2|x3),
  formula(y~x1+x2+x3+x4)
)

我有一个接受不同参数的函数(1- 子样本,2- weights 参数的列名,3- 要尝试的公式列表和 4- 要使用的 data.frame)

f1 <- function(samp, dat, forms, wgt){
  baselm <- lm(y~x1, data = dat[samp,], weights = dat[samp,wgt])
  lapply(forms, update, object = baselm)
}

如果我调用该函数,我会得到一个错误:

f1(1:66, dat = dd, forms = ls.form, wgt = "wg")
 Error in is.data.frame(data) : object 'dat' not found 

我真的不明白为什么它找不到dat 对象,它应该是函数环境的一部分。问题出在代码的update 部分,就像您从函数中删除这一行一样,代码可以正常工作。

最后,这个函数会被lapply调用

lapply(list(1:66, 33:99), f1, dat=dd, forms = ls.form, wgt="wg")

【问题讨论】:

    标签: r lapply lm


    【解决方案1】:

    接受的错误有效,但我继续挖掘并找到了这个旧的 r-help 问题 (here),它提供了更多选项和解释。我想我会把它贴在这里以防其他人需要它。

    【讨论】:

      【解决方案2】:

      我认为你的问题是由于 lm 使用的范围规则,坦率地说,这在 r-squared 中是一个痛苦。

      一种选择是使用do.call 使其工作,但是当它解析输入以提供用于标准打印方法的调用时,您会得到一些难看的输出。

      f1 <- function(samp, dat, forms, wgt){
        baselm <- do.call(lm,list(formula=y~x1, data = dat[samp,], weights = dat[samp,wgt]))
        lapply(forms, update, object = baselm)
      }
      

      更好的方法是使用eval(substitute(...)) 构造,它可以提供您最初预期的输出:

      f2 <- function(samp, dat, forms, wgt){
        baselm <- eval(substitute(lm(y~x1, data = dat[samp,], weights = dat[samp,wgt])))
        lapply(forms, update, object = baselm)
      }
      

      【讨论】:

      • 您的两个选项都适用于我的主代码,谢谢!我感觉它比我的原始代码慢(没有重量参数),但没有对它进行基准测试,因为它仍然非常有用。 do.call 是最快的。无论如何,对于一个非常晦涩的错误,这是一个非常晦涩的修复......我今天的两个错误都很奇怪,需要我进行更多研究才能真正了解发生了什么!
      • R Inferno 第 8 圈第 8.1.70 节涉及这些问题:burns-stat.com/pages/Tutor/R_inferno.pdf
      【解决方案3】:

      此类范围问题在lm 对象中很常见。您可以通过指定正确的评估环境来解决此问题:

      f1 <- function(samp, dat, forms, wgt){
        baselm <- lm(y~x1, data = dat[samp,], weights = dat[samp,wgt])
        mods <- lapply(forms, update, object = baselm, evaluate = FALSE)
        e <- environment()
        lapply(mods, eval, envir = e)
      }
      
      f1(1:66, dat = dd, forms = ls.form, wgt = "wg")
      #works
      

      【讨论】:

      • 您的示例每次都有效,但是当我将其应用于我的实际问题时,我仍然得到object 'dd.temp.ref' not found,我设法通过在主环境中加载不同的参数来使其工作,但是作为一旦我重新启动 R,它就不再工作了......如果我找到一种重现它的方法,我会继续挖掘并回来。
      • 我不知道出了什么问题,但我的电话f2 &lt;- function(ref.id, dat, ff, wgt){ dd.temp.ref &lt;- dat[ref.id,] baselm &lt;- lm(ff[[length(ff)]], data = dd.temp.ref, weights = dd.temp.ref[,wgt]) mods &lt;- lapply(ff, update, object = baselm, evaluate = FALSE) e &lt;- environment() all.mod &lt;- lapply(mods, eval, envir = e) } 与您的电话几乎相同,但失败了???是我的电脑吗??
      • 不,不一样。您正在以编程方式将公式传递给 lm,这很可能会产生额外的范围界定问题。您应该计算语言以将公式插入 lm 表达式,然后在函数环境中评估该表达式。我有一个答案显示如何做到这一点,但是当我不必用手机搜索它时已经很困难了。
      • 你说得对,问题出在我提取列表中的公式...我没想到会这样,考虑到identical(formula(y~x1+x2), ls.form[[1]])TRUE...这么多奇怪今天的错误...@James 解决方案的工作,所以不急,但是我有兴趣查看您正在谈论的解决方案。感谢您在有机会时发布它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-16
      • 1970-01-01
      • 2013-02-11
      • 2021-06-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多