【问题标题】:How to write trycatch in R如何在 R 中编写 trycatch
【发布时间】:2012-08-24 23:58:01
【问题描述】:

我想写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 错误时,输出将是:“web URL is wrong, can't get”。
  2. 当URL错误时,代码并没有停止,而是继续下载直到URL列表的末尾?

【问题讨论】:

    标签: r exception exception-handling try-catch r-faq


    【解决方案1】:

    那么:欢迎来到 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))(参见?tryCatch 中的参数errorwarning)。这些可以是已经存在的函数,但您也可以在 tryCatch() 中定义它们(就像我在上面所做的那样)。

    选择处理函数的特定返回值的含义

    因为我们已经指定了NA 应该在出错的情况下返回,所以y 中的第三个元素是NA。如果我们选择NULL 作为返回值,y 的长度将只是2 而不是3,因为lapply() 将简单地“忽略”返回值NULL。另请注意,如果您未通过return() 指定显式 返回值,则处理程序函数将返回NULL(即在出现错误或警告情况时)。

    “不需要的”警告消息

    由于warn=FALSE 似乎没有任何效果,抑制警告的另一种方法(在这种情况下并不真正感兴趣)是使用

    suppressWarnings(readLines(con=url))
    

    而不是

    readLines(con=url, warn=FALSE)
    

    多个表达式

    请注意,如果您将多个表达式括在大括号中(就像我在 finally 部分中说明的那样),您还可以将多个表达式放在“实际表达式部分”(tryCatch() 的参数 expr)中。

    【讨论】:

    • @seancarmody: true ;-) 我只是习惯于将更长/更复杂的字符串放在一起,我必须通过实际写出来控制空格。
    • 你应该使用paste0
    • paste0() 在基地。在内部,paste()paste0()paste.c 中调用 do_paste。唯一的区别是 paste0() 不传递 sep 参数。
    • @JulienNavarre:请记住,“尝试部分”总是返回 last 对象(目前readLines(con=url, warn=FALSE) 是可能出错的实际情况)。因此,如果您想添加一条消息,您需要将实际的 retun 值存储在一个变量中:out &lt;- readLines(con=url, warn=FALSE) 后跟 message("Everything worked") 后跟 out 以使其成为实际返回的最后一个对象跨度>
    • 很棒的例子并且有据可查。我是否可以要求删除所有关于 paste / paste0 等琐碎问题的评论者,以免我们在本节中充斥不相关的内容?谢谢。
    【解决方案2】:

    tryCatch 具有稍微复杂的语法结构。但是,一旦我们理解了构成完整 tryCatch 调用的 4 个部分,如下所示,就很容易记住了:

    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/

    希望这有帮助。

    【讨论】:

      【解决方案3】:

      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

      【讨论】:

      • cat("web url is wrong, can't get")替换error-handler-code
      • 你忽略了消息捕捉
      【解决方案4】:

      这里是一个简单的例子

      # 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)
              }
          )
      }
      

      如果您还想捕获“警告”,只需添加类似于error= 部分的warning=

      【讨论】:

      • expr 部分是否应该有大括号,因为有两行而不是一行?
      • 谢谢!经过仔细检查,我认为不需要大括号
      • 感谢您的仔细检查。当我运行你的代码时,我得到了Error: unexpected ')' in " )"Error: unexpected ')' in " )"。添加一对大括号即可解决问题。
      • 对于大多数用例来说,你是对的,谢谢!它已被修复。
      【解决方案5】:

      由于我刚刚失去了两天的生命试图解决 tryCatch 的 irr 函数,我想我应该分享我的智慧(以及缺少的东西)。仅供参考 - irr 是 FinCal 的一个实际函数,在这种情况下,在大型数据集的少数情况下会出错。

      1. 将 tryCatch 设置为函数的一部分。例如:

        irr2 <- function (x) {
          out <- tryCatch(irr(x), error = function(e) NULL)
          return(out)
        }
        
      2. 要使错误(或警告)起作用,您实际上需要创建一个函数。我最初的错误部分只是写了error = return(NULL) 并且所有值都返回null。

      3. 记得创建一个子输出(比如我的“out”)和return(out)

      【讨论】:

      • 为什么需要 3 号?
      猜你喜欢
      • 1970-01-01
      • 2018-12-23
      • 1970-01-01
      • 2014-09-08
      • 1970-01-01
      • 2017-06-10
      相关资源
      最近更新 更多