代码之家  ›  专栏  ›  技术社区  ›  Eduardo Leoni

调试lappy/sapply调用

r
  •  29
  • Eduardo Leoni  · 技术社区  · 16 年前

    使用lappy和friends编写的代码通常比循环更容易看,也更危险。我和下一个家伙一样喜欢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
    

    7 回复  |  直到 16 年前
        1
  •  26
  •   Shane    16 年前

    如果使用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"
    

        2
  •  25
  •   Pascal Pascal    16 年前

    options(error = browser) 
    

    options(error = recover)
    

    完成后,恢复到标准行为:

    options(error = NULL)
    
        3
  •  9
  •   Collin    16 年前

    .inform = TRUE :

    library(plyr)
    laply(x, function(x) 1/x, .inform = TRUE)
    
        4
  •  2
  •   ephpostfacto    16 年前

    正如杰弗里所说:

    > 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
    

    For循环在R中很慢,但是除非你真的需要速度,否则我会用一种简单的迭代方法来克服混乱的列表理解。

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

        5
  •  1
  •   griffin    16 年前

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

        6
  •  0
  •   geoffjentry    16 年前

    可以调试()函数,也可以在函数体中放置一个browser()。这只有在您没有无数次迭代的情况下才特别有用。

    另外,我个人并没有这样做,但我怀疑您可以将browser()作为tryCatch()的一部分放入其中,以便在生成错误时可以使用browser()接口。

        7
  •  0
  •   Jake    16 年前

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

    因此,不要胡说八道<-sapply(x,函数(x){x+1})

    我得说,

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

    并将debug(myfn)与选项(error=recover)一起使用。

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

    更好的方法是设计一个它必须通过的myfn(x)测试,并确保它在接受sapply测试之前通过了上述测试。我只有一半的时间有耐心去做这件事。