Wie schreibe ich Trycatch in R.

342

Ich möchte trycatchCode schreiben , um Fehler beim Herunterladen aus dem Internet zu beheben.

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)

Diese beiden Anweisungen werden erfolgreich ausgeführt. Unten erstelle ich eine nicht existierende Webadresse:

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

url[1]ist nicht vorhanden. Wie schreibt man eine trycatchSchleife (Funktion), damit:

  1. Wenn die URL falsch ist, lautet die Ausgabe: "Web-URL ist falsch, kann nicht erhalten".
  2. Wenn die URL falsch ist, stoppt der Code nicht, sondern wird bis zum Ende der Liste der URLs weiter heruntergeladen.
Dd Pp
quelle

Antworten:

625

Na dann: Willkommen in der R-Welt ;-)

Bitte schön

Code einrichten

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

Anwenden des Codes

> 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

Untersuchung der Ausgabe

> 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

Zusätzliche Bemerkungen

tryCatch

tryCatchGibt den Wert zurück, der der Ausführung zugeordnet ist, es exprsei denn, es liegt ein Fehler oder eine Warnung vor. In diesem Fall können bestimmte Rückgabewerte (siehe return(NA)oben) durch Angabe einer entsprechenden Handlerfunktion angegeben werden (siehe Argumente errorund warningin ?tryCatch). Dies können bereits vorhandene Funktionen sein, aber Sie können sie auch innerhalb definieren tryCatch()(wie oben beschrieben).

Die Auswirkungen der Auswahl bestimmter Rückgabewerte der Handlerfunktionen

Wie wir festgelegt haben , dass NAim Fehlerfall zurückgegeben werden soll, in das dritte Element yist NA. Wenn wir würden gewählt , NULLden Rückgabewert sein, die Länge ywäre einfach gewesen, 2statt 3wie lapply()einfach „ignorieren“ Rückgabewerte , die sind NULL. Beachten Sie auch , dass , wenn Sie keine angeben expliziten Rückgabewert über return()die Handler - Funktionen zurückkehren NULL(dh im Falle eines Fehlers oder eines Warnzustand).

Warnmeldung "Unerwünscht"

Da warn=FALSEdies keine Auswirkungen zu haben scheint, besteht eine alternative Möglichkeit zur Unterdrückung der Warnung (die in diesem Fall nicht wirklich von Interesse ist) in der Verwendung

suppressWarnings(readLines(con=url))

anstatt

readLines(con=url, warn=FALSE)

Mehrere Ausdrücke

Beachten Sie, dass Sie auch mehrere Ausdrücke in den Teil "Tatsächliche Ausdrücke" (Argument exprvon tryCatch()) einfügen können, wenn Sie sie in geschweifte Klammern setzen (genau wie im finallyTeil dargestellt).

Rappster
quelle
Wenn die erste Zeichenfolge in Ihren pasteFunktionen mit einem Leerzeichen endet, lassen Sie das Leerzeichen und das Leerzeichen sep=""weg.
Seancarmody
2
@seancarmody: true ;-) Ich bin es einfach gewohnt, längere / kompliziertere Strings zusammenzustellen, wenn ich Leerzeichen kontrollieren muss, indem ich sie tatsächlich ausschreibe.
Rappster
3
Sie sollten dafür verwenden paste0!
Seancarmody
6
paste0() ist in der Basis. Intern beide paste()und paste0()Anruf do_pastein paste.c . Der einzige Unterschied ist, paste0()dass kein sepArgument übergeben wird.
Jthetzel
1
@ JulienNavarre: Denken Sie daran, dass der "Versuchsteil" immer das letzte Objekt zurückgibt (derzeit readLines(con=url, warn=FALSE)ist dies das eigentliche Objekt , das schief gehen könnte). Wenn Sie also eine Nachricht hinzufügen möchten, müssen Sie den tatsächlichen Retun-Wert in einer Variablen speichern: out <- readLines(con=url, warn=FALSE)gefolgt von message("Everything worked")gefolgt out, um dies zum letzten Objekt zu machen, das tatsächlich zurückgegeben wird
Rappster
69

R verwendet Funktionen zum Implementieren des Try-Catch-Blocks:

Die Syntax sieht ungefähr so ​​aus:

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

In tryCatch () können zwei 'Bedingungen' behandelt werden: 'Warnungen' und 'Fehler'. Das Wichtigste beim Schreiben jedes Codeblocks ist der Ausführungsstatus und der Umfang. @Quelle

heretolearn
quelle
5
Ersetzen error-handler-codedurchcat("web url is wrong, can't get")
Seancarmody
2
Sie haben das Fangen von Nachrichten
ausgelassen
52

tryCatchhat eine leicht komplexe Syntaxstruktur. Sobald wir jedoch die 4 Teile verstanden haben, die einen vollständigen tryCatch-Aufruf darstellen, wie unten gezeigt, wird es leicht, sich zu erinnern:

Ausdruck : [ Erforderlich ] R-Code (s), die ausgewertet werden sollen

Fehler : [ Optional ] Was soll ausgeführt werden, wenn beim Auswerten der Codes in Ausdruck ein Fehler aufgetreten ist?

Warnung : [ Optional ] Was sollte ausgeführt werden, wenn beim Auswerten der Codes in Ausdruck eine Warnung aufgetreten ist?

Schließlich : [ Optional ] Was sollte unmittelbar vor dem Beenden des tryCatch-Aufrufs ausgeführt werden, unabhängig davon, ob expr erfolgreich ausgeführt wurde, mit einem Fehler oder einer Warnung

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

Ein Spielzeugbeispiel zur Berechnung des Protokolls eines Werts könnte daher folgendermaßen aussehen:

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

Nun werden drei Fälle ausgeführt:

Ein gültiger Fall

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

Ein "Warn" -Fall

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

Ein "Fehler" -Fall

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

Ich habe über einige nützliche Anwendungsfälle geschrieben, die ich regelmäßig verwende. Weitere Details finden Sie hier: https://rsangole.netlify.com/post/try-catch/

Hoffe das ist hilfreich.

Rahul
quelle
34

Hier ein einfaches Beispiel :

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

Wenn Sie auch eine "Warnung" erfassen möchten, fügen Sie einfach warning=ähnlich wie das error=Teil hinzu.

Paul
quelle
1
Sollte es um das exprTeil geschweifte Klammern geben , da es zwei Linien anstelle von einer gibt?
Paul
Vielen Dank! Nach doppelter Überprüfung sehe ich keine Notwendigkeit für geschweifte Klammern
Paul
Vielen Dank für die Überprüfung. Wenn ich Ihren Code starte, habe ich Error: unexpected ')' in " )"und Error: unexpected ')' in " )". Das Hinzufügen eines Paares geschweifter Klammern löst das Problem.
Paul
Für die meisten Anwendungsfälle haben Sie Recht, danke! Es wurde behoben.
Paul
23

Da ich gerade zwei Tage meines Lebens verloren habe, als ich versucht habe, tryCatch für eine irr-Funktion zu lösen, dachte ich, ich sollte meine Weisheit teilen (und was fehlt). FYI - irr ist in diesem Fall eine tatsächliche Funktion von FinCal, bei der in einigen Fällen Fehler in einem großen Datensatz aufgetreten sind.

  1. Richten Sie tryCatch als Teil einer Funktion ein. Zum Beispiel:

    irr2 <- function (x) {
      out <- tryCatch(irr(x), error = function(e) NULL)
      return(out)
    }
  2. Damit der Fehler (oder die Warnung) funktioniert, müssen Sie tatsächlich eine Funktion erstellen. Ich habe ursprünglich für den Fehlerteil gerade geschrieben error = return(NULL)und ALLE Werte sind null zurückgekommen.

  3. Denken Sie daran, eine Unterausgabe (wie mein "out") zu erstellen und zu return(out).

James
quelle
3
Warum ist Nummer 3 notwendig?
Jan-Glx