开发者

Exception handling in R [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
开发者_如何学Python

We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.

Closed 6 years ago.

Improve this question

Does anyone have examples/tutorials of exception handling in R? The official documentation is very terse.


Basically you want to use the tryCatch() function. Look at help("tryCatch") for more details.

Here's a trivial example (keep in mind that you can do whatever you want with an error):

vari <- 1
tryCatch(print("passes"), error = function(e) print(vari), finally=print("finished")) 
tryCatch(stop("fails"), error = function(e) print(vari), finally=print("finished")) 

Have a look at these related questions:

  • Equivalent of "throw" in R
  • catching an error and then branching logic
  • https://stackoverflow.com/search?q=[r]+trycatch


Besides Shane's answer pointing you to other StackOverflow discussions, you could try a code search feature. This original answer pointed to Google's Code Search has since been discontinued, but you can try

  • Github search as e.g. in this query for tryCatch in language=R;
  • Ohloh/Blackduck Code search eg this query for tryCatch in R files
  • the Debian code search engine on top of the whole Debian archive

Just for the record, there is also try but tryCatch may be preferable. I tried a quick count at Google Code Search but try gets too many false positives for the verb itself -- yet it seems tryCatch is more widely used.


This result from a related google search helped me: http://biocodenv.com/wordpress/?p=15.

for(i in 1:16){
result <- try(nonlinear_modeling(i));
if(class(result) == "try-error") next;
}


The function trycatch() is fairly straight forward, and there are plenty of good tutorials on that. A excellent explanation of error handling in R can be found in Hadley Wickham's book Advanced-R, and what follows is a very basic intro to withCallingHandlers() and withRestarts() in as few words as possible:

Lets say a low level programmer writes a function to calculate the absolute value. He isn't sure how to calculate it, but knows how to construct an error and diligently conveys his naiveté:

low_level_ABS <- function(x){
    if(x<0){
        #construct an error
        negative_value_error <- structure(
                    # with class `negative_value`
                    class = c("negative_value","error", "condition"),
                    list(message = "Not Sure what to with a negative value",
                         call = sys.call(), 
                         # and include the offending parameter in the error object
                         x=x))
        # raise the error
        stop(negative_value_error)
    }
    cat("Returning from low_level_ABS()\n")
    return(x)
}

A mid-level programmer also writes a function to calculate the absolute value, making use of the woefully incomplete low_level_ABS function. He knows that the low level code throws a negative_value error when the value of x is negative and suggests an solution to the problem, by establishing a restart which allows users of mid_level_ABS to control the way in which mid_level_ABS recovers (or doesn't) from a negative_value error.

mid_level_ABS <- function(y){
    abs_y <- withRestarts(low_level_ABS(y), 
                          # establish a restart called 'negative_value'
                          # which returns the negative of it's argument
                          negative_value_restart=function(z){-z}) 
    cat("Returning from mid_level_ABS()\n")
    return(abs_y)
}

Finally, a high level programmer uses the mid_level_ABS function to calculate the absolute value, and establishes a condition handler which tells the mid_level_ABS to recover from a negative_value error by using the restart handler.

high_level_ABS <- function(z){
    abs_z <- withCallingHandlers(
            # call this function
            mid_level_ABS(z) ,
            # and if an `error` occurres
            error = function(err){
                # and the `error` is a `negative_value` error
                if(inherits(err,"negative_value")){
                    # invoke the restart called 'negative_value_restart'
                    invokeRestart('negative_value_restart', 
                                     # and invoke it with this parameter
                                     err$x) 
                }else{
                    # otherwise re-raise the error
                    stop(err)
                }
            })
    cat("Returning from high_level_ABS()\n")
    return(abs_z)
}

The point of all this is that by using withRestarts() and withCallingHandlers(), the function high_level_ABS was able to tell mid_level_ABS how to recover from errors raised by low_level_ABS error without stopping the execution of mid_level_ABS, which is something you can't do with tryCatch():

> high_level_ABS(3)
Returning from low_level_ABS()
Returning from mid_level_ABS()
Returning from high_level_ABS()
[1] 3
> high_level_ABS(-3)
Returning from mid_level_ABS()
Returning from high_level_ABS()
[1] 3

In practice, low_level_ABS represents a function that mid_level_ABS calls a lot (maybe even millions of times), for which the correct method of error handling may vary by situation, and choice of how to handle specific errors is left to higher level functions (high_level_ABS).


The restart function is very important in R inherited from Lisp. It is useful if you want to call some function in the loop body and you just want the program to continue if the function call collapses. Try this code:

for (i in 1:20) withRestarts(tryCatch(
if((a <- runif(1))>0.5) print(a) else stop(a),
finally = print("loop body finished!")), 
abort = function(){})
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜