Obsługa wyjątków w R [zamknięte]

97

Czy ktoś ma przykłady / tutoriale obsługi wyjątków w R? Oficjalna dokumentacja jest bardzo zwięzła.

gappy
źródło
1
Ten jest również dobrym przykładem: stackoverflow.com/q/12193779/2026975 .
imriss
Uważam, że ten post na blogu jest całkiem przydatny: http://mazamascience.com/WorkingWithData/?p=912
paul_dg

Odpowiedzi:

31

Oprócz odpowiedzi Shane'a wskazującej na inne dyskusje StackOverflow, możesz wypróbować funkcję wyszukiwania kodu. Ta pierwotna odpowiedź wskazała na wyszukiwarkę Google Code Search, która została wycofana, ale możesz spróbować

Tak dla przypomnienia, jest też, tryale tryCatchmoże być lepsze. Próbowałem szybko policzyć w Google Code Search, ale próbowałem uzyskać zbyt wiele fałszywych alarmów dla samego czasownika - ale wydaje się, że tryCatchjest on częściej używany.

Dirk Eddelbuettel
źródło
Może ten przykład mógłby pomóc: http://stackoverflow.com/a/12195574/2026975
imriss
Wyszukiwania Github jest prawdopodobnie przyzwoity zamiennik dla nieistniejącego link.
Gregor Thomas
Wszystkie linki są zepsute.
Toros91
60

Zasadniczo chcesz użyć tej tryCatch()funkcji. Więcej informacji znajdziesz w pomocy („tryCatch”).

Oto trywialny przykład (pamiętaj, że z błędem możesz zrobić, co chcesz):

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

Spójrz na te powiązane pytania:

Shane
źródło
8

Ta funkcja trycatch()jest dość prosta i jest na jej temat wiele dobrych tutoriali. Doskonałe wyjaśnienie obsługi błędów w R można znaleźć w książce Hadleya Wickhama Advanced-R , a poniżej znajduje się bardzo podstawowe wprowadzenie do withCallingHandlers()i withRestarts()w jak najmniejszej liczbie słów:

Powiedzmy, że programista niskiego poziomu pisze funkcję obliczającą wartość bezwzględną. Nie jest pewien, jak to obliczyć, ale wie, jak skonstruować błąd i pilnie przekazuje swoją naiwność:

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

Programista średniego poziomu pisze również funkcję obliczającą wartość bezwzględną, wykorzystując żałośnie niekompletną low_level_ABSfunkcję. Wie, że kod niskiego poziomu generuje negative_value błąd, gdy wartość xjest ujemna, i sugeruje rozwiązanie problemu, ustanawiając sposób, restartktóry pozwala użytkownikom mid_level_ABSkontrolować sposób, w jaki mid_level_ABSodzyskuje (lub nie) po negative_valuebłędzie.

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

Wreszcie, programista wysoki poziom wykorzystuje mid_level_ABSfunkcję do obliczania wartości bezwzględnej, a ustanawia obsługi warunek, który mówi mid_level_ABS, aby odzyskać od negative_valuebłędu za pomocą obsługi restartu.

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

Chodzi o to, że używając withRestarts()i withCallingHandlers(), funkcja high_level_ABSbyła w stanie powiedzieć, mid_level_ABSjak naprawić błędy wywołane przez low_level_ABSbłąd bez zatrzymywania wykonywania mid_level_ABS, czego nie można zrobić 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

W praktyce low_level_ABSreprezentuje funkcję, która mid_level_ABSwywołuje dużo (może nawet miliony razy), dla której poprawna metoda obsługi błędów może się różnić w zależności od sytuacji, a wybór sposobu obsługi określonych błędów pozostawia się funkcjom wyższego poziomu ( high_level_ABS).

Jthorpe
źródło
7

Funkcja restartu jest bardzo ważna w R dziedziczonej z Lispa. Jest to przydatne, jeśli chcesz wywołać jakąś funkcję w treści pętli i chcesz, aby program kontynuował działanie, jeśli wywołanie funkcji się zwinie. Wypróbuj ten kod:

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(){})
Xin Guo
źródło