Ответ 1
Используйте стандартные методы отладки R, чтобы точно остановиться при возникновении ошибки:
options(error = browser)
или
options(error = recover)
По завершении верните стандартное поведение:
options(error = NULL)
Код, написанный с использованием lapply и друзей, обычно проще на глазах и больше Rish, чем на петлях. Я обожаю себя так же, как и следующий парень, но как мне отлаживать его, когда что-то идет не так? Например:
> ## 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?
Используйте стандартные методы отладки R, чтобы точно остановиться при возникновении ошибки:
options(error = browser)
или
options(error = recover)
По завершении верните стандартное поведение:
options(error = NULL)
Если вы завернете свою внутреннюю функцию с помощью инструкции 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"
В этом случае вы можете увидеть, какой индекс терпит неудачу.
Используйте пакет plyr, .inform = TRUE
:
library(plyr)
laply(x, function(x) 1/x, .inform = TRUE)
Как сказал 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 медленнее, но если вам действительно не нужна скорость, я бы пошел с простым итеративным подходом к запутанному пониманию списка.
Если мне нужно выяснить код на лету, я всегда пойду:
sapply(x, function(x) {
browser()
...
})
И напишите код внутри функции, чтобы я увидел, что я получаю.
- Дэн
Использование отладки или браузера не является хорошей идеей в этом случае, потому что это будет часто останавливать ваш код. Вместо этого используйте Try или TryCatch и рассмотрите ситуацию, когда она возникает.
Вы можете отлаживать() функцию или помещать браузер() внутри тела. Это особенно полезно, если у вас нет итераций gajillion для работы.
Кроме того, я лично не сделал этого, но я подозреваю, что вы можете поместить браузер() как часть tryCatch(), так что при возникновении ошибки вы можете использовать интерфейс browser().
Я столкнулся с той же проблемой и имел тенденцию делать мои вызовы с (l) (m) (s) (t) применимыми к функции, которые я могу отлаживать().
Итак, вместо blah < -sapply (x, function (x) {x + 1})
Я бы сказал,
myfn<-function(x){x+1}
blah<-sapply(x,function(x){myfn(x)})
и используйте debug (myfn) с параметрами (ошибка = восстановление).
Мне также нравится совет о вставке print() строк здесь и там, чтобы увидеть, что происходит.
Еще лучше разработать тест myfn (x), который он должен пройти, и убедиться, что он проходит тест, прежде чем подвергать его дряблости. У меня есть только терпение к этому примерно в половине случаев.