Ik wil tryCatch
-code schrijven om fouten bij het downloaden van internet op te lossen.
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)
Deze twee instructies zijn succesvol uitgevoerd. Hieronder maak ik een niet-bestaand webadres aan:
url <- c("xxxxx", "http://en.wikipedia.org/wiki/Xz")
url[1]
bestaat niet. Hoe schrijf je een tryCatch
lus (functie) zodat:
- Als de URL onjuist is, is de uitvoer: “web-URL is verkeerd, kan niet worden opgehaald”.
- Als de URL fout is, stopt de code niet, maar gaat door met downloaden tot het einde van de lijst met URL’s?
Antwoord 1, autoriteit 100%
Welnu: welkom in de R-wereld 😉
Hier ga je
De code instellen
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)
}
De code toepassen
> 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
De output onderzoeken
> 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
Aanvullende opmerkingen
tryCatch
tryCatch
retourneert de waarde die is gekoppeld aan het uitvoeren van expr
tenzij er een fout of waarschuwing is. In dit geval kunnen specifieke retourwaarden (zie return(NA)
hierboven) worden gespecificeerd door een respectieve handlerfunctie op te geven (zie argumenten error
en warning
in ?tryCatch
). Dit kunnen functies zijn die al bestaan, maar je kunt ze ook definiëren binnen tryCatch()
(zoals ik hierboven deed).
De implicaties van het kiezen van specifieke retourwaarden van de handlerfuncties
Omdat we hebben gespecificeerd dat NA
moet worden geretourneerd in geval van een fout, is het derde element in y
NA
. Als we NULL
als retourwaarde hadden gekozen, zou de lengte van y
gewoon 2
zijn geweest in plaats van 3
als lapply()
zal eenvoudigweg waarden “negeren” die NULL
zijn. Merk ook op dat als u geen expliciete retourwaarde opgeeft via return()
, de handlerfuncties NULL
zullen retourneren (dwz in het geval van een fout of een waarschuwingsconditie).
“Ongewenst” waarschuwingsbericht
Omdat warn=FALSE
geen effect lijkt te hebben, is een alternatieve manier om de waarschuwing te onderdrukken (wat in dit geval niet echt van belang is) het gebruik van
suppressWarnings(readLines(con=url))
in plaats van
readLines(con=url, warn=FALSE)
Meerdere uitdrukkingen
Merk op dat u ook meerdere uitdrukkingen in het “werkelijke uitdrukkingsgedeelte” (argument expr
van tryCatch()
) kunt plaatsen als u ze tussen accolades plaatst (net als Ik illustreerde in het finally
deel).
Antwoord 2, autoriteit 12%
tryCatch
heeft een enigszins complexe syntaxisstructuur. Zodra we echter de 4 delen begrijpen die een complete tryCatch-aanroep vormen, zoals hieronder weergegeven, wordt het gemakkelijk te onthouden:
expr: [Vereist] R-code(s) die moeten worden geëvalueerd
fout : [Optioneel] Wat moet er worden uitgevoerd als er een fout is opgetreden tijdens het evalueren van de codes in expr
waarschuwing: [Optioneel] Wat moet er worden uitgevoerd als er een waarschuwing is opgetreden tijdens het evalueren van de codes in expr
eindelijk : [Optioneel] Wat moet worden uitgevoerd net voordat de tryCatch-aanroep wordt gestopt, ongeacht of expr succesvol is uitgevoerd, met een fout of met een waarschuwing
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...
}
)
Een speelgoedvoorbeeld om het logboek van een waarde te berekenen kan er dus als volgt uitzien:
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.')
}
)
}
Nu bezig met drie zaken:
Een geldige zaak
log_calculator(10)
# 2.30258509299405
# Successfully executed the log(x) call.
# All done, quitting.
Een waarschuwingsgeval
log_calculator(-10)
# Caught an warning!
# <simpleWarning in log(x): NaNs produced>
# All done, quitting.
Een “fout”-geval
log_calculator("log_me")
# Caught an error!
# <simpleError in log(x): non-numeric argument to mathematical function>
# All done, quitting.
Ik heb geschreven over een aantal handige use-cases die ik regelmatig gebruik. Vind hier meer details: https://rsangole.netlify.com/post/try-catch/
Ik hoop dat dit nuttig is.
Antwoord 3, autoriteit 10%
R gebruikt functies voor het implementeren van try-catch-blok:
De syntaxis ziet er ongeveer als volgt uit:
result = tryCatch({
expr
}, warning = function(warning_condition) {
warning-handler-code
}, error = function(error_condition) {
error-handler-code
}, finally={
cleanup-code
})
In tryCatch() zijn er twee voorwaarden die kunnen worden afgehandeld: waarschuwingen en fouten . Het belangrijkste om te begrijpen bij het schrijven van elk codeblok is de staat van uitvoering en de reikwijdte.
@source
Antwoord 4, autoriteit 7%
Hier is een duidelijk voorbeeld:
# 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)
}
)
}
Als u ook een “waarschuwing” wilt vastleggen, voegt u gewoon warning=
toe, vergelijkbaar met het gedeelte error=
.
Antwoord 5, autoriteit 4%
Omdat ik net twee dagen van mijn leven heb verloren bij het oplossen van tryCatch voor een irr-functie, dacht ik dat ik mijn wijsheid moest delen (en wat er ontbreekt). Ter info – irr is een echte functie van FinCal, in dit geval werden er in een paar gevallen fouten gemaakt op een grote dataset.
-
Stel tryCatch in als onderdeel van een functie. Bijvoorbeeld:
irr2 <- function (x) { out <- tryCatch(irr(x), error = function(e) NULL) return(out) }
-
Om de fout (of waarschuwing) te laten werken, moet je eigenlijk een functie maken. Ik schreef oorspronkelijk voor het foutgedeelte
error = return(NULL)
en ALLE waarden kwamen terug op null. -
Vergeet niet om een sub-output te maken (zoals mijn “out”) en om
return(out)
te maken.