Error handling refers to the process of managing and responding to errors or exceptions that occur during the execution of a program. In R, error handling ensures that your code can gracefully handle unexpected situations, such as invalid inputs or runtime errors, without crashing.
Error handling is crucial because it:
The following functions are designed to handle errors in the R programming language.
The try() function is used to execute an expression and
handle errors that occur. It returns the result of the expression if
successful, or an error object if an error occurs.
division <- function(x, y) {
result <- try(x / y, silent = TRUE)
if (inherits(result, 'try-error')) {
cat("\nBoth x and y must be numeric, got", typeof(x), "and", typeof(y))
return(NA)
}
return(result)
}
The following will be successful.
division(x = 8, y = 5)
## [1] 1.6
The following will print a custom error message, and return
NA as the result because there is an attempt to divide
8 by M which is a character.
division(x = 8, y = "M")
##
## Both x and y must be numeric, got double and character
## [1] NA
The tryCatch() function is used to execute an expression
and catch any errors, warnings, or messages that occur during its
execution. This function helps in managing errors gracefully by
providing alternative actions or custom messages when an error occurs,
rather than stopping the entire program.
The syntax is given as follows
tryCatch(
expr,
error = function(e) {
},
warning = function(w) {
},
finally = {
}
)
where
expr: The expression to be evaluated.
error: A function to handle errors.
warning: A function to handle warnings.
finally: A block of code that will be executed regardless of whether an error or warning occurred.
write_df_to_csv <- function(file_path, df) {
tryCatch({
write.csv(df, file = file_path, row.names = FALSE)
},
error = function(e) {
cat("Error while writing to file:", conditionMessage(e))
})
}
The following will write the dataset women to the
default working directory (in my case, it is my documents
directory).
write_df_to_csv(file_path = "P:/women.csv", df = women)
## Warning in file(file, ifelse(append, "a", "w")): cannot open file
## 'P:/women.csv': No such file or directory
## Error while writing to file: cannot open the connection
The following will fail because I do not have a directory named
H on my local drive.
write_df_to_csv(file_path = "H:/women.csv", df = women)
## Warning in file(file, ifelse(append, "a", "w")): cannot open file
## 'H:/women.csv': No such file or directory
## Error while writing to file: cannot open the connection
The stop() function is used to generate an error and
halt execution. It is useful for indicating that something has gone
wrong and should be addressed.
The stopifnot() function checks if the provided
conditions are TRUE. If any condition is FALSE, it generates an
error.
The warning() function generates a warning message
without halting execution. It is useful for non-critical issues that
should be brought to the user’s attention.
Example
We use the example of calculating body mass index do demonstrate the
application of stop()
stopifnot()andwarning()`.
bmi <- function(weight, height) {
# if weight or height is not a vector, e.g. its a matrix, then first
# convert it to a vector but remember to inform the user of this action
if (!is.vector(weight)) {
warning("weight was converted from ", class(weight), " to a vector")
weight = c(weight)
}
if (!is.vector(height)) {
warning("height was converted from ", class(height), " to a vector")
height = c(height)
}
# using `stop` to check length
if (length(weight) != length(height)) {
stop(
"weight and height must have same number of elements ",
"got ", length(weight), " and ", length(height), " elements ",
"respectively"
)
}
# using `stopifnot` to validate that both are numeric
stopifnot(is.numeric(weight), is.numeric(height))
# calculate the body mass index
calculate_bmi <- function(height, weight) {
return(weight / (height ^ 2))
}
bmi <- mapply(calculate_bmi, height, weight)
suspicious_bmi = bmi[bmi > 500 | bmi < 5]
n = length(suspicious_bmi)
if (n > 0) {
index = ifelse(n == 1, "index", "indices")
suspicious_bmi_str = paste(round(suspicious_bmi, 4), collapse = ", ")
warning("Body mass ", index, ": ", suspicious_bmi_str, " are suspicious.")
}
df = data.frame(weight, height, bmi)
return(df)
}
Apply the functio
Will work successfully
weight <- c(94, 85, 82, 70, 83, 85, 77, 80, 64, 57, 98, 95)
height <- height <- c(1.62, 1.82, 1.66, 1.85, 1.88, 1.52, 1.71, 1.86, 1.72, 1.68, 1.88, 1.68)
bmi(weight = weight, height = height)
## weight height bmi
## 1 94 1.62 35.81771
## 2 85 1.82 25.66115
## 3 82 1.66 29.75758
## 4 70 1.85 20.45289
## 5 83 1.88 23.48348
## 6 85 1.52 36.79017
## 7 77 1.71 26.33289
## 8 80 1.86 23.12406
## 9 64 1.72 21.63332
## 10 57 1.68 20.19558
## 11 98 1.88 27.72748
## 12 95 1.68 33.65930
Will work but return a warning message
weight <- c(94, 85, 2000, 70, 83, 85, 77, 80, 64, 57, 98, 95)
height <- height <- c(1.62, 1.82, 1.66, 1.85, 1.88, 1.52, 1.71, 1.86, 1.72, 1.68, 1.88, 168)
bmi(weight = weight, height = height)
## Warning in bmi(weight = weight, height = height): Body mass indices: 725.7947,
## 0.0034 are suspicious.
## weight height bmi
## 1 94 1.62 35.81771071
## 2 85 1.82 25.66115203
## 3 2000 1.66 725.79474525
## 4 70 1.85 20.45288532
## 5 83 1.88 23.48347669
## 6 85 1.52 36.79016620
## 7 77 1.71 26.33288875
## 8 80 1.86 23.12406059
## 9 64 1.72 21.63331531
## 10 57 1.68 20.19557823
## 11 98 1.88 27.72747850
## 12 95 168.00 0.00336593
Will crush because length are not the same (uncomment last line)
weight <- c(94, 85, 82, 70, 83, 85, 77, 80, 64, 57, 98, 95)
height <- height <- c(1.62, 1.82, 1.66, 1.85, 1.88, 1.52, 1.71)
#bmi(weight = weight, height = height)
Will crush because one is character due to presence of “N/A”
(uncomment last line) - this is as result of the
stopifnot() function validation.
weight <- c(94, 85, 82, 70, 83, 85, 77, 80, 64, 57, 98, 95)
height <- height <- c(1.62, 1.82, "N/A", 1.85, 1.88, 1.52, 1.71, 1.86, 1.72, 1.68, 1.88, 1.68)
#bmi(weight = weight, height = height)