【问题标题】:Debugging lapply/sapply calls调试 lapply/sapply 调用
【发布时间】:2010-11-26 14:34:40
【问题描述】:

使用 lapply 和friends 编写的代码通常比循环更容易看,也更Rish。我和下一个人一样喜欢 lapply,但是当出现问题时我该如何调试它呢?例如:

> ## a list composed of numeric elements 
> x <- as.list(-2:2)
> ## turn one of the elements into characters
> x[[2]] <- "what?!?"
> 
> ## using sapply
> sapply(x, function(x) 1/x)
Error in 1/x : non-numeric argument to binary operator

如果我使用了 for 循环:

> y <- rep(NA, length(x))
> for (i in 1:length(x)) {
+     y[i] <-  1/x[[i]]
+ }
Error in 1/x[[i]] : non-numeric argument to binary operator

但我会知道错误发生在哪里:

> i
[1] 2

使用 lapply/sapply 时应该怎么做?

【问题讨论】:

  • 这可能是一个不受欢迎的回应,但经过 15 年的 R 开发,我几乎总是发现暂时转换为 for 循环以找到破坏我的代码的边缘情况更容易。此外,从 for 循环开始而不是 sapply/lapply 可以简化您的初始过程(您可以在重要时重构代码以提高速度/性能 - 但首先它需要工作!)

标签: r


【解决方案1】:

在这种情况下使用调试或浏览器不是一个好主意,因为它会频繁地停止您的代码。请改用 Try 或 TryCatch,并在出现情况时处理。

【讨论】:

    【解决方案2】:

    就像 geoffjentry 说的:

    > sapply(x, function(x) {
      res <- tryCatch(1 / x,
                      error=function(e) {
                              cat("Failed on x = ", x, "\n", sep="") ## browser()
                              stop(e)
                            })
    })
    

    另外,你的 for 循环可以重写得更简洁(可能慢一点):

    > y <- NULL
    > for (xi in x)
        y <- c(y, 1 / xi)
    
    Error in 1/xi : non-numeric argument to binary operator
    

    R 中的 For 循环很慢,但除非你真的需要速度,否则我会使用简单的迭代方法来解决令人困惑的列表理解。

    如果我需要即时找出一些代码,我总是会去:

    sapply(x, function(x) {
      browser()
      ...
    })
    

    然后从函数内部编写代码,以便我看到我得到了什么。

    -- 丹

    【讨论】:

    • 对 for 循环的错误调用。这会使事情大大变慢。
    • @hadley ...因为在每个循环步骤中都需要重新分配整个数组(保留内存,复制旧数据):) y &lt;- numeric(length(x)) 应该是最快的预分配方式。
    【解决方案3】:

    我也遇到过同样的问题,并且倾向于使用 (l)(m)(s)(t) 调用我可以调试的函数。

    所以,不是废话

    我会说,

     myfn<-function(x){x+1}
     blah<-sapply(x,function(x){myfn(x)})
    

    并使用带有选项的调试(myfn)(错误=恢复)。

    我也喜欢关于在这里和那里粘贴 print() 行以查看发生了什么的建议。

    更好的方法是设计一个必须通过的 myfn(x) 测试,并确保它在对其进行 sapply 之前通过所述测试。我只有大约一半的时间对此有耐心。

    【讨论】:

    • 或者只是blah&lt;-sapply(x, mfn)。你不应该同时需要debug 和恢复`
    【解决方案4】:

    使用标准的 R 调试技术在错误发生时准确停止:

    options(error = browser) 
    

    options(error = recover)
    

    完成后,恢复标准行为:

    options(error = NULL)
    

    【讨论】:

      【解决方案5】:

      使用 plyr 包,.inform = TRUE:

      library(plyr)
      laply(x, function(x) 1/x, .inform = TRUE)
      

      【讨论】:

        【解决方案6】:

        你可以 debug() 函数,或者在 body 中放一个 browser()。仅当您没有大量迭代需要完成时,这才特别有用。

        另外,我没有亲自这样做,但我怀疑您可以将 browser() 作为 tryCatch() 的一部分放入,这样当生成错误时,您可以使用 browser() 接口。

        【讨论】:

          【解决方案7】:

          如果你用 try() 语句包装你的内部函数,你会得到更多信息:

          > sapply(x, function(x) try(1/x))
          Error in 1/x : non-numeric argument to binary operator
          [1] "-0.5"                                                    
          [2] "Error in 1/x : non-numeric argument to binary operator\n"
          [3] "Inf"                                                     
          [4] "1"                                                       
          [5] "0.5"
          

          在这种情况下,您可以看到哪个索引失败。

          【讨论】:

            猜你喜欢
            • 2021-02-05
            • 1970-01-01
            • 1970-01-01
            • 2013-10-31
            • 2019-03-29
            • 2015-02-20
            • 1970-01-01
            • 1970-01-01
            • 2023-03-06
            相关资源
            最近更新 更多