Исправлена ​​ошибка в большом `sapply`

Этот вопрос может или не может быть вдохновлен моей потерей всего трехчасового пробега геокодирования, потому что одно из значений возвращает ошибку. Вызовите жалкие (вниз) голоса.

В основном была ошибка, возвращаемая внутри функции, называемой sapply. У меня был options(error=recover), но, несмотря на просмотр всех доступных мне уровней, я не мог найти места, где результаты (тысячи успешных) вызовов FUN были сохранены в памяти.

Некоторые из объектов, которые я обнаружил при просмотре самих себя, дали ошибки, когда я попытался их исследовать, утверждая, что ссылки больше недействительны. К сожалению, я потерял конкретное сообщение об ошибке.

Вот быстрый пример, который, хотя он не реплицирует ссылочную ошибку (которая, как я подозреваю, связана с исчезающими средами и, вероятно, несущественна), демонстрирует, что я не вижу способа сохранить данные, которые уже были обработаны.

Есть ли такая методика?

Обратите внимание, что с тех пор я реализовал свою ошибку и вставил еще более надежную обработку ошибок, чем раньше, чем через try, но я ищу способ восстановить содержимое ex post, а не ex ante.

Функция тестирования

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()) находится следующий код:

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

Я хочу получить значение ans, если сбой в вызове lapply.

Ответ 1

Я пытаюсь понять, почему try() здесь не путь? Если sapply() не работает по какой-либо причине, то вы

  • хочу справиться с этой ошибкой
  • оттуда

Почему вы хотите, чтобы весь процесс анализа и обработки данных остановился только на ошибку? Это то, что вы, кажется, предлагаете. Вместо того, чтобы пытаться восстановить то, что уже было сделано, напишите свой код, чтобы он просто продолжался, запись ошибки имела место, но также изящно переходила к следующему этапу процесса.

Это немного запутанно, потому что пример, который вы даете, изобретен (если вы знали, что может вызвать ошибку, с которой вы могли бы справиться без 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(), заполнив предварительно выделенный список, когда я повторил.

Ответ 2

Вы никогда не назначали промежуточные значения ни на что. Я не понимаю, почему вы думаете, что для божественности должны быть какие-то недра. Вам нужно каким-то образом записать значения:

 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 как способ восстановления параметров par, когда построение не пошло. (Мне не удалось заставить его работать с on.exit(res <- x).

Ответ 3

Возможно, я не понимаю, и это, безусловно, замедлит вас, но как насчет глобального назначения каждый раз?

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