Как написать trycatch на R

Я хочу написать trycatch код для устранения ошибки при загрузке из Интернета.

url <- c(
    "http://stat.ethz.ch/R-manual/R-devel/library/base/html/connections.html",
    "http://en.wikipedia.org/wiki/Xz")
y <- mapply(readLines, con=url)

Эти два оператора работают успешно. Ниже я создаю несуществующий веб-адрес:

url <- c("xxxxx", "http://en.wikipedia.org/wiki/Xz")

url[1] не существует. Как написать цикл (функцию) trycatch, чтобы:

  1. Если URL-адрес неверен, вывод будет: «URL-адрес неправильный, невозможно получить».
  2. Когда URL-адрес неправильный, код не останавливается, а продолжает загрузку до конца списка URL-адресов?

person Dd Pp    schedule 30.08.2012    source источник


Ответы (5)


Что ж: добро пожаловать в мир R ;-)

Ну вот

Настройка кода

urls <- c(
    "http://stat.ethz.ch/R-manual/R-devel/library/base/html/connections.html",
    "http://en.wikipedia.org/wiki/Xz",
    "xxxxx"
)
readUrl <- function(url) {
    out <- tryCatch(
        {
            # Just to highlight: if you want to use more than one 
            # R expression in the "try" part then you'll have to 
            # use curly brackets.
            # 'tryCatch()' will return the last evaluated expression 
            # in case the "try" part was completed successfully

            message("This is the 'try' part")

            readLines(con=url, warn=FALSE) 
            # The return value of `readLines()` is the actual value 
            # that will be returned in case there is no condition 
            # (e.g. warning or error). 
            # You don't need to state the return value via `return()` as code 
            # in the "try" part is not wrapped inside a function (unlike that
            # for the condition handlers for warnings and error below)
        },
        error=function(cond) {
            message(paste("URL does not seem to exist:", url))
            message("Here's the original error message:")
            message(cond)
            # Choose a return value in case of error
            return(NA)
        },
        warning=function(cond) {
            message(paste("URL caused a warning:", url))
            message("Here's the original warning message:")
            message(cond)
            # Choose a return value in case of warning
            return(NULL)
        },
        finally={
        # NOTE:
        # Here goes everything that should be executed at the end,
        # regardless of success or error.
        # If you want more than one expression to be executed, then you 
        # need to wrap them in curly brackets ({...}); otherwise you could
        # just have written 'finally=<expression>' 
            message(paste("Processed URL:", url))
            message("Some other message at the end")
        }
    )    
    return(out)
}

Применение кода

> y <- lapply(urls, readUrl)
Processed URL: http://stat.ethz.ch/R-manual/R-devel/library/base/html/connections.html
Some other message at the end
Processed URL: http://en.wikipedia.org/wiki/Xz
Some other message at the end
URL does not seem to exist: xxxxx
Here's the original error message:
cannot open the connection
Processed URL: xxxxx
Some other message at the end
Warning message:
In file(con, "r") : cannot open file 'xxxxx': No such file or directory

Исследование вывода

> head(y[[1]])
[1] "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"      
[2] "<html><head><title>R: Functions to Manipulate Connections</title>"      
[3] "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"
[4] "<link rel=\"stylesheet\" type=\"text/css\" href=\"R.css\">"             
[5] "</head><body>"                                                          
[6] ""    

> length(y)
[1] 3

> y[[3]]
[1] NA

Дополнительные примечания

tryCatch

tryCatch возвращает значение, связанное с выполнением expr, если нет ошибки или предупреждения. В этом случае конкретные возвращаемые значения (см. return(NA) выше) могут быть указаны путем предоставления соответствующей функции-обработчика (см. Аргументы error и warning в ?tryCatch). Это могут быть уже существующие функции, но вы также можете определить их в tryCatch() (как я сделал выше).

Последствия выбора конкретных возвращаемых значений функций-обработчиков

Как мы указали, что NA должен быть возвращен в случае ошибки, третий элемент в y - это NA. Если бы мы выбрали NULL в качестве возвращаемого значения, длина y была бы просто 2 вместо 3, поскольку lapply() просто игнорирует возвращаемые значения, которые равны NULL. Также обратите внимание, что если вы не укажете явное возвращаемое значение через return(), функции-обработчики вернут NULL (т. Е. В случае ошибки или условия предупреждения).

Нежелательное предупреждающее сообщение

Поскольку warn=FALSE, похоже, не имеет никакого эффекта, альтернативным способом подавления предупреждения (которое в данном случае не представляет особого интереса) является использование

suppressWarnings(readLines(con=url))

вместо того

readLines(con=url, warn=FALSE)

Несколько выражений

Обратите внимание, что вы также можете поместить несколько выражений в фактическую часть выражений (аргумент expr из tryCatch()), если заключите их в фигурные скобки (как я проиллюстрировал в части finally).

person Community    schedule 30.08.2012
comment
Учитывая, что первая строка в ваших paste функциях заканчивается пробелом, почему бы не опустить пробел и sep=""? - person seancarmody; 30.08.2012
comment
@seancarmody: true ;-) Я так привык складывать более длинные / сложные строки, что мне приходилось контролировать пробелы, фактически записывая их. - person Rappster; 30.08.2012
comment
Для этого нужно использовать paste0! - person seancarmody; 30.08.2012
comment
paste0() находится в базе. Внутри paste() и paste0() вызывают do_paste в paste.c . Единственная разница в том, что paste0() не передает аргумент sep. - person jthetzel; 30.08.2012
comment
@jthetzel + @seancarmody: извините, правда для R-2.15.1. У меня была устаревшая версия R (2.14.1), и тогда такой функции не было. Очень хорошо, ИМХО, это должно было быть поведением paste по умолчанию с самого начала - person Rappster; 30.08.2012
comment
is out будет NULL, если warning выдается в tryCatch в вашем примере? - person RNA; 11.02.2014
comment
@RNA: на самом деле, я думаю, что это небольшая ошибка в моем коде, поскольку out не определен в области видимости функции warning. Просто взглянув на него, я не уверен, что R примет значение для out с помощью лексической области видимости. Я проверю - person Rappster; 11.02.2014
comment
@RNA: обновил ответ. Если вы ничего не укажете явно, функции-обработчики вернут NULL. Возврат out в случае предупреждения не имел для меня никакого смысла, поэтому я изменил его на return(NULL) только в иллюстративных целях. Надеюсь, теперь все ясно. - person Rappster; 11.02.2014
comment
@Rappster: да, спасибо. и не могли бы вы объяснить последнюю строчку return (out)too? Разве это не похоже на return в функции предупреждения? - person RNA; 11.02.2014
comment
Мне было интересно, почему мой бит error всегда выполнялся - фигурные скобки исправили это! - person Matthew Wise; 02.07.2014
comment
Как я могу отобразить сообщение, если часть попытки была успешно завершена, пожалуйста? - person Julien Navarre; 23.04.2015
comment
@JulienNavarre: помните, что часть try всегда возвращает последний объект (в настоящее время readLines(con=url, warn=FALSE), что на самом деле может пойти не так). Поэтому, если вы хотите добавить сообщение, вам нужно будет сохранить фактическое значение возврата в переменной: out <- readLines(con=url, warn=FALSE), за которым следует message("Everything worked"), за которым следует out, чтобы сделать это последним фактически возвращаемым объектом. - person Rappster; 23.04.2015
comment
Как сохранить информацию о том, что пошло не так? error = function (cond) {message (cond)} не возвращает такой же объем информации, который отображается без trycatch. Кто-нибудь сталкивался с этой проблемой? Как распечатать информацию о строке, вызвавшей ошибку. - person user1198407; 07.05.2015
comment
Попробуйте conditionMessage (cond). Это фактическое сообщение об ошибке в виде символьной строки. - person Rappster; 07.05.2015
comment
Фантастический пример, хорошо задокументированный. Могу я попросить всех комментаторов, ответивших на несерьезные вопросы, такие как paste / paste0, удалить, чтобы мы не забивали этот раздел ненужным материалом? Спасибо. - person Lazarus Thurston; 31.01.2020
comment
Есть ли (хороший) способ использовать одну и ту же функциональность как для предупреждения, так и для случая ошибки? Или мне нужно скопировать код? - person dpelisek; 23.10.2020

tryCatch имеет немного сложную синтаксическую структуру. Однако, как только мы поймем 4 части, которые составляют полный вызов tryCatch, как показано ниже, становится легко запомнить:

expr: [Обязательный] код (ы) R для оценки

error: [Необязательно] Что должно выполняться, если при оценке кодов в expr произошла ошибка

предупреждение: [Необязательно] Что должно выполняться, если при оценке кодов в expr возникло предупреждение

finally: [Необязательно] Что должно выполняться непосредственно перед завершением вызова tryCatch, независимо от того, было ли expr выполнено успешно, с ошибкой или с предупреждением

tryCatch(
    expr = {
        # Your code...
        # goes here...
        # ...
    },
    error = function(e){ 
        # (Optional)
        # Do this if an error is caught...
    },
    warning = function(w){
        # (Optional)
        # Do this if an warning is caught...
    },
    finally = {
        # (Optional)
        # Do this at the end before quitting the tryCatch structure...
    }
)

Таким образом, игрушечный пример для вычисления журнала значения может выглядеть так:

log_calculator <- function(x){
    tryCatch(
        expr = {
            message(log(x))
            message("Successfully executed the log(x) call.")
        },
        error = function(e){
            message('Caught an error!')
            print(e)
        },
        warning = function(w){
            message('Caught an warning!')
            print(w)
        },
        finally = {
            message('All done, quitting.')
        }
    )    
}

Теперь выполняем три случая:

Действительный случай

log_calculator(10)
# 2.30258509299405
# Successfully executed the log(x) call.
# All done, quitting.

Случай с предупреждением

log_calculator(-10)
# Caught an warning!
# <simpleWarning in log(x): NaNs produced>
# All done, quitting.

Случай "ошибки"

log_calculator("log_me")
# Caught an error!
# <simpleError in log(x): non-numeric argument to mathematical function>
# All done, quitting.

Я написал о некоторых полезных сценариях использования, которые использую регулярно. Дополнительные сведения см. Здесь: https://rsangole.netlify.com/post/try-catch/ < / а>

Надеюсь, это будет полезно.

person Rahul    schedule 20.12.2018
comment
действительно хороший ответ! благодарю вас! - person FMM; 11.01.2021

R использует функции для реализации блока try-catch:

Синтаксис примерно такой:

result = tryCatch({
    expr
}, warning = function(warning_condition) {
    warning-handler-code
}, error = function(error_condition) {
    error-handler-code
}, finally={
    cleanup-code
})

В tryCatch () есть два «условия», которые могут быть обработаны: «предупреждения» и «ошибки». При написании каждого блока кода важно понимать состояние выполнения и область действия. @source

person heretolearn    schedule 30.08.2012
comment
Заменить error-handler-code на cat("web url is wrong, can't get") - person seancarmody; 30.08.2012
comment
вы упустили ловушку сообщений - person rawr; 16.12.2015

Вот простой пример:

# Do something, or tell me why it failed
my_update_function <- function(x){
    tryCatch(
        # This is what I want to do...
        {
        y = x * 2
        return(y)
        },
        # ... but if an error occurs, tell me what happened: 
        error=function(error_message) {
            message("This is my custom message.")
            message("And below is the error message from R:")
            message(error_message)
            return(NA)
        }
    )
}

Если вы также хотите зафиксировать «предупреждение», просто добавьте warning= аналогично части error=.

person Paul    schedule 13.04.2017
comment
Следует ли заключать часть expr в фигурные скобки, поскольку вместо одной линии две? - person Paul; 15.08.2018
comment
Спасибо! После двойной проверки не вижу необходимости в фигурных скобках - person Paul; 15.08.2018
comment
Спасибо за двойную проверку. Когда я запустил ваш код, я получил Error: unexpected ')' in " )" и Error: unexpected ')' in " )". Добавление пары фигурных скобок решает проблему. - person Paul; 16.08.2018
comment
В большинстве случаев вы правы, спасибо! Это было исправлено. - person Paul; 10.11.2018

Поскольку я только что потерял два дня своей жизни, пытаясь решить tryCatch для функции irr, я подумал, что должен поделиться своей мудростью (и тем, чего не хватает). FYI - irr - это фактическая функция FinCal в этом случае, когда в нескольких случаях возникали ошибки на большом наборе данных.

  1. Настройте tryCatch как часть функции. Например:

    irr2 <- function (x) {
      out <- tryCatch(irr(x), error = function(e) NULL)
      return(out)
    }
    
  2. Чтобы ошибка (или предупреждение) работала, вам действительно нужно создать функцию. Я изначально для части ошибки просто написал error = return(NULL), и ВСЕ значения вернулись нулевыми.

  3. Не забудьте создать подвывод (например, мой "out") и return(out).

person James    schedule 25.09.2016
comment
Зачем нужен номер 3? - person jan-glx; 21.12.2017