在大的'sapply`中从错误中解脱出来

时间:2012-10-22 01:11:50

标签: r error-handling

这个问题可能会或可能不会受到我失去整个3小时地理编码运行的启发,因为其中一个值返回了错误。提示怜悯(下)投票。

基本上在sapply调用的函数中返回了一个错误。我有options(error=recover),但尽管浏览了我可用的每个级别,但我找不到任何将(数千次成功)调用FUN的结果存储在内存中的地方。

我在浏览周围时发现的一些对象在我尝试检查时发现错误,声称引用不再有效。不幸的是,我丢失了特定的错误消息。

这是一个快速的例子,虽然它没有复制引用错误(我怀疑它与消失的环境有关并且可能并不重要),但它确实证明我看不到保存已处理数据的方法。

有这样的技术吗?

请注意,我已经意识到我的错误并插入了比通过try之前存在的更强大的错误处理,但我正在寻找一种方法来恢复内容事后而不是事前。

测试功能

sapply( seq(10), function(x) {
  if(x==5) stop("Error!")
  return( "important data" )
} )

互动探索

> sapply( seq(10), function(x) {
+   if(x==5) stop("Error!")
+   return( "important data" )
+ } )
Error in FUN(1:10[[5L]], ...) : Error!

Enter a frame number, or 0 to exit   

1: sapply(seq(10), function(x) {
    if (x == 5) 
        stop("Error!")
    return("important data")
})
2: lapply(X = X, FUN = FUN, ...)
3: FUN(1:10[[5]], ...)

Selection: 3
Called from: FUN(1:10[[5L]], ...)
Browse[1]> ls()
[1] "x"
Browse[1]> x
[1] 5
Browse[1]> 
Enter a frame number, or 0 to exit   

1: sapply(seq(10), function(x) {
    if (x == 5) 
        stop("Error!")
    return("important data")
})
2: lapply(X = X, FUN = FUN, ...)
3: FUN(1:10[[5]], ...)

Selection: 2
Called from: lapply(X = X, FUN = FUN, ...)
Browse[1]> ls()
[1] "FUN" "X"  
Browse[1]> X
 [1]  1  2  3  4  5  6  7  8  9 10
Browse[1]> FUN
function(x) {
  if(x==5) stop("Error!")
  return( "important data" )
}
Browse[1]> 
Enter a frame number, or 0 to exit   

1: sapply(seq(10), function(x) {
    if (x == 5) 
        stop("Error!")
    return("important data")
})
2: lapply(X = X, FUN = FUN, ...)
3: FUN(1:10[[5]], ...)

Selection: 1
Called from: sapply(seq(10), function(x) {
    if (x == 5) 
        stop("Error!")
    return("important data")
})
Browse[1]> ls()
[1] "FUN"       "simplify"  "USE.NAMES" "X"        
Browse[1]> X
 [1]  1  2  3  4  5  6  7  8  9 10
Browse[1]> USE.NAMES
[1] TRUE
Browse[1]> simplify
[1] TRUE
Browse[1]> FUN
function(x) {
  if(x==5) stop("Error!")
  return( "important data" )
}
Browser[1]> Q

要清楚,我希望找到的是矢量:

[1] "important data" "important data" "important data" "important data"

换句话说,到目前为止已经完成的内部循环的结果。

编辑:使用C代码更新

内部.Internal(lapply())following code

PROTECT(ans = allocVector(VECSXP, n));
...
for(i = 0; i < n; i++) {
   ...
   tmp = eval(R_fcall, rho);
   ...
   SET_VECTOR_ELT(ans, i, tmp);
}

ans的任何来电失败时,我想lapply

3 个答案:

答案 0 :(得分:4)

我很难理解为什么try()不是这样的?如果sapply()因任何原因失败,那么

  1. 想要妥善处理这个失败
  2. 从那里继续
  3. 为什么您希望整个数据分析/处理步骤仅针对错误停止?这似乎是你提出的建议。不要试图恢复已经完成的工作,而是编写代码以便继续执行,记录错误,同时优雅地转移到流程的下一步。

    这有点令人费解,因为你给出的例子是人为的(如果你知道什么会导致错误,你可以在没有try()的情况下处理),但请耐心等待:

    foo <- function(x) {
        res <- try({
            if(x==5) {
                stop("Error!")
            } else {
                "important data"
            }
        })
        if(inherits(res, "try-error"))
            res <- "error occurred"
        res
    }
    
    > sapply( seq(10), foo)
    Error in try({ : Error!
     [1] "important data" "important data" "important data" "important data"
     [5] "error occurred" "important data" "important data" "important data"
     [9] "important data" "important data"
    

    在后台运行我的工作站需要几周才完成的工作后,我很快学会了围绕单个语句编写大量try()个调用而不是大块代码,这样一旦发生错误,我很快就会得到超出该迭代/步骤,对正在运行的作业影响最小;换句话说,如果一个特定的R调用失败,我会返回一些内容,这些内容会很好地插入sapply()(或任何函数)返回的对象中。

    对于任何更复杂的事情,我可能会使用lapply()

    foo2 <- function(x) {
        res <- try({
            if(x==5) {
                stop("Error!")
            } else {
                lm(rnorm(10) ~ runif(10))
            }
        })
        if(inherits(res, "try-error"))
            res <- "error occurred"
        res
    }
    
    out <- lapply(seq(10), foo2)
    str(out, max = 1)
    

    因为你想要列表而不是试图将更复杂的对象简化为简单的东西:

    >     out <- lapply(seq(10), foo2)
    Error in try({ : Error!
    > str(out, max = 1)
    List of 10
     $ :List of 12
      ..- attr(*, "class")= chr "lm"
     $ :List of 12
      ..- attr(*, "class")= chr "lm"
     $ :List of 12
      ..- attr(*, "class")= chr "lm"
     $ :List of 12
      ..- attr(*, "class")= chr "lm"
     $ : chr "error occurred"
     $ :List of 12
      ..- attr(*, "class")= chr "lm"
     $ :List of 12
      ..- attr(*, "class")= chr "lm"
     $ :List of 12
      ..- attr(*, "class")= chr "lm"
     $ :List of 12
      ..- attr(*, "class")= chr "lm"
     $ :List of 12
      ..- attr(*, "class")= chr "lm"
    

    那就是说,我可能已经通过for()循环完成了这项工作,在迭代时填写预分配列表。

答案 1 :(得分:1)

您从未将中间值分配给任何内容。我不明白为什么你认为应该有任何内脏。您需要以某种方式记录值:

 res <- sapply( seq(10), function(x) { z <- x
                                   on.exit(res <<- x);
                                   if(x==5) stop("Error!")
 } )
Error in FUN(1:10[[5L]], ...) : Error!
 res
#[1] 5

on.exit方法在?par页面上说明,作为在绘图出错时恢复标准设置的方法。 (我无法使用on.exit(res <- x)

答案 2 :(得分:1)

也许我不理解,这肯定会减慢你的速度,但每次全球任务呢?

safety <- vector()
sapply( seq(10), function(x) {
  if(x==5) stop("Error!")
  assign('safety', c(safety, x), envir = .GlobalEnv)
  return( "important data" )
} )

收率:

> safety <- vector()
> sapply( seq(10), function(x) {
+   if(x==5) stop("Error!")
+   assign('safety', c(safety, x), envir = .GlobalEnv)
+   return( "important data" )
+ } )
Error in FUN(1:10[[5L]], ...) : Error!
> safety
[1] 1 2 3 4