trycatch error handling and for loops error - r

Having trouble handling errors in a for loop because of the scope in the tryCatch error function, I imagine.
The error handles correctly in the sense that it skips and continues working, but whats in the error function doesn't write into the data frame (d), thus when an error ocurrs, I get an output with the number of row, instead of NULLS or NA's.
What am I missing? This is a visual example of the loops taking place.
function<-function(vector){
n<-length(vector)
d<-data.frame(a=1:n,
b=1:n,
c=1:n)
for (i in 1:n)
{
tryCatch({
#create an m for every i in vector
m<-foo(i)
for (j in 1:length(m[,1]))
{ #for every element in m, transform with a function
m[j]<-foo2(j)
}
#now, with m transformed, fill every element of d (so that it matches elements of vector)
d[i,]$a = sum(m)
d[i,]$b = sd(m)
d[i,]$c = mean(m)
#end try
}, error = function(e){
#if there is an erorr in m<-foo(i), I want it to place NULL or NA values in each column of d
d[i,]$a = NULL
d[i,]$b = NULL
d[i,]$c = NULL
}
#end trycatch
)
#end loop
}
#end function
}

Related

How do you generate the output of for loop and if statement into a list or vector?

I have tried the following but the output brings an argument stating,
Error in append("0") : argument "values" is miss
for (rowz in final_data$Ingridients) {
Cobalt_row<-lst()
if (sum(str_detect(rowz, 'Cobalt'))>0) {
Cobalt_row.append(1)
} else {
Cobalt_row<-append(0)
}
print(Cobalt_row)
}
I intended to loop through the list and generate a boolean of ones and twos depending on
whether or not I had the value.
Please help
Without the data, I can't test it, but this should work:
Cobalt_row<-lst()
k <- 1
for (rowz in final_data$Ingridients) {
Cobalt_row[[k]] <- ifelse(str_detect(rowz, 'Cobalt'), 1, 0)
k <- k+1
}
or even simpler if you need a list:
Cobalt_row <- as.list(as.numeric(str_detect(final_data$Ingredients, "Cobalt")))

How to skip the error file and continue to read the next one when batch reading files in R [duplicate]

I've read a few other SO questions about tryCatch and cuzzins, as well as the documentation:
Exception handling in R
catching an error and then branching logic
How can I check whether a function call results in a warning?
Problems with Plots in Loop
but I still don't understand.
I'm running a loop and want to skip to next if any of a few kinds of errors occur:
for (i in 1:39487) {
# EXCEPTION HANDLING
this.could.go.wrong <- tryCatch(
attemptsomething(),
error=function(e) next
)
so.could.this <- tryCatch(
doesthisfail(),
error=function(e) next
)
catch.all.errors <- function() { this.could.go.wrong; so.could.this; }
catch.all.errors;
#REAL WORK
useful(i); fun(i); good(i);
} #end for
(by the way, there is no documentation for next that I can find)
When I run this, R honks:
Error in value[[3L]](cond) : no loop for break/next, jumping to top level
What basic point am I missing here? The tryCatch's are clearly within the for loop, so why doesn't R know that?
The key to using tryCatch is realising that it returns an object. If there was an error inside the tryCatch then this object will inherit from class error. You can test for class inheritance with the function inherit.
x <- tryCatch(stop("Error"), error = function(e) e)
class(x)
"simpleError" "error" "condition"
Edit:
What is the meaning of the argument error = function(e) e? This baffled me, and I don't think it's well explained in the documentation. What happens is that this argument catches any error messages that originate in the expression that you are tryCatching. If an error is caught, it gets returned as the value of tryCatch. In the help documentation this is described as a calling handler. The argument e inside error=function(e) is the error message originating in your code.
I come from the old school of procedural programming where using next was a bad thing. So I would rewrite your code something like this. (Note that I removed the next statement inside the tryCatch.):
for (i in 1:39487) {
#ERROR HANDLING
possibleError <- tryCatch(
thing(),
error=function(e) e
)
if(!inherits(possibleError, "error")){
#REAL WORK
useful(i); fun(i); good(i);
}
} #end for
The function next is documented inside ?for`.
If you want to use that instead of having your main working routine inside an if, your code should look something like this:
for (i in 1:39487) {
#ERROR HANDLING
possibleError <- tryCatch(
thing(),
error=function(e) e
)
if(inherits(possibleError, "error")) next
#REAL WORK
useful(i); fun(i); good(i);
} #end for
I found other answers very confusing. Here is an extremely simple implementation for anyone who wants to simply skip to the next loop iteration in the event of an error
for (i in 1:10) {
skip_to_next <- FALSE
# Note that print(b) fails since b doesn't exist
tryCatch(print(b), error = function(e) { skip_to_next <<- TRUE})
if(skip_to_next) { next }
}
for (i in -3:3) {
#ERROR HANDLING
possibleError <- tryCatch({
print(paste("Start Loop ", i ,sep=""))
if(i==0){
stop()
}
}
,
error=function(e) {
e
print(paste("Oops! --> Error in Loop ",i,sep = ""))
}
)
if(inherits(possibleError, "error")) next
print(paste(" End Loop ",i,sep = ""))
}
The only really detailed explanation I have seen can be found here: http://mazamascience.com/WorkingWithData/?p=912
Here is a code clip from that blog post showing how tryCatch works
#!/usr/bin/env Rscript
# tryCatch.r -- experiments with tryCatch
# Get any arguments
arguments <- commandArgs(trailingOnly=TRUE)
a <- arguments[1]
# Define a division function that can issue warnings and errors
myDivide <- function(d, a) {
if (a == 'warning') {
return_value <- 'myDivide warning result'
warning("myDivide warning message")
} else if (a == 'error') {
return_value <- 'myDivide error result'
stop("myDivide error message")
} else {
return_value = d / as.numeric(a)
}
return(return_value)
}
# Evalute the desired series of expressions inside of tryCatch
result <- tryCatch({
b <- 2
c <- b^2
d <- c+2
if (a == 'suppress-warnings') {
e <- suppressWarnings(myDivide(d,a))
} else {
e <- myDivide(d,a) # 6/a
}
f <- e + 100
}, warning = function(war) {
# warning handler picks up where error was generated
print(paste("MY_WARNING: ",war))
b <- "changing 'b' inside the warning handler has no effect"
e <- myDivide(d,0.1) # =60
f <- e + 100
return(f)
}, error = function(err) {
# warning handler picks up where error was generated
print(paste("MY_ERROR: ",err))
b <- "changing 'b' inside the error handler has no effect"
e <- myDivide(d,0.01) # =600
f <- e + 100
return(f)
}, finally = {
print(paste("a =",a))
print(paste("b =",b))
print(paste("c =",c))
print(paste("d =",d))
# NOTE: Finally is evaluated in the context of of the inital
# NOTE: tryCatch block and 'e' will not exist if a warning
# NOTE: or error occurred.
#print(paste("e =",e))
}) # END tryCatch
print(paste("result =",result))
One thing I was missing, which breaking out of for loop when running a function inside a for loop in R makes clear, is this:
next doesn't work inside a function.
You need to send some signal or flag (e.g., Voldemort = TRUE) from inside your function (in my case tryCatch) to the outside.
(this is like modifying a global, public variable inside a local, private function)
Then outside the function, you check to see if the flag was waved (does Voldemort == TRUE). If so you call break or next outside the function.

Specify the calling function for an error message in R

I'm working on an R package where the same input-checking functions are called by multiple "actual" functions that are exported to users. If I use a simple stop() call, the error message is going to say that an error occurred in the input-checking function, which is not that useful...
I thought I'd get around this by wrapping the call to the input-checking function inside a tryCatch(), and then handling the error in the outer function. This does mostly what I want, but doesn't quite give the output that I'd like. The closest I've come is the following:
f <- function(i) {
tryCatch({
check_input(i)
}, error = function(e) stop("in f: ", e$message, call. = FALSE)
)
}
check_input <- function(i) {
if(i < 0)
stop("i is negative, value given was ", i)
}
f(-1)
# Error: in f: i is negative, value given was -1
Ideally, I'd like the error message to be
Error in f: i is negative, value given was -1
, which would be the case if stop were called within f() instead of check_input().
Here's how you can grab the name of the function from the call stack and paste it in to the error message
f <- function(i) {
check_input(i)
}
g <- function(i) {
check_input(i)
}
check_input <- function(i, from=deparse(sys.calls()[[sys.nframe()-1]][[1]])) {
getmsg <- function(m) ifelse(!is.null(from), paste0("in ", from, ": ", m), m)
if(i < 0)
stop(getmsg(paste0("i is negative, value given was ", i)), call. = FALSE)
}
f(-1)
# Error: in f: i is negative, value given was -1
g(-1)
# Error: in g: i is negative, value given was -1
You could also call check_input(i, from="otherfunction") to show whatever function name you want or check_input(i, from=NULL) to suppress the function name.

Logging and writing error messages to a dataframe

I intend to record the errors in my R code while calling functions in a dataframe (ERR_LOG, say). I want to use 'try' to identify errors while calling a function,if any.The dataframe(ERR_LOG) will have the following columns :
Time : The time at which the function was called (Sys.time)
Loc : For which function call was this error recorded (name of the
function)
Desc : Description of the error which R throws at us (Error message
in R)
Example :
First I would like to initialize a blank dataframe 'ERR_LOG' with these columns
Then write the function
f <- function(a){
x <- a*100
return(x)
}
Now I put the output of the call to 'f' in 'chk'
chk <- try(f())
The above call gives the error 'Error in a * 100 : 'a' is missing' (description of the error)
Check
if(inherits(chk,'try-error'))
{then I want to populate ERR_LOG and stop the code execution}
How can this be done in R?
use tryCatch instead of try
Then inside tryCatch(), use the argument error=function(e){}
e will have an element named message, which is what you would like
Use the following call with browser to explore e$message:
x <- tryCatch(stop("This is your error message"), error=function(e) {browser()})
Note that your function need not be anonymous.
MyErrorParser <- function(e) {
m <- e$message
if (grepl("something", m))
do something
return (something_else)
}
## THEN
tryCatch(stop("This is a test"), error=MyErrorParser)

R: "Subscript out of bounds" error on function

I continue to get an error on my function, possibly I'm overlooking something simple. I cannot run the code without getting an error when applying the function.
k.nn <- function(k,p1,p) {
k > 0
K <-length(k)
p=matrix()
for (i in p) {
matrix <- cbind(p,p1[1],p1[2])
d <- sqrt((matrix[,1]-matrix[,3])^2+(matrix[,2]-matrix[,4])^2)
}
##use the sort function to find the smallest distance from 1:k and return all nearest k values
sort.d <- function(x) { #implement bubble sort
N=length(x)
N>0
c=class(x)
for (n in length(x):2) { #distinguish the last term in the vector, name it, much be of x length, consists an error of length 1. Error if you compute n in length(x):1, cover length of 1
if(length(x)<2)
return(x)
for (m in 1:(n - 1)) { #distinguish the first term in the vector, name it
if(x[m]>x[m + 1]) { #begin comparing each term to neighboring term
swap<-x[m]
x[m]<-x[m + 1]
x[m + 1]<-swap
}
}
}
return(x)
}
sorted=sort.d(d)
for (n in k){
print(sorted[1:k])}
}
p=matrix(c(6.9,7.6,7.1,.4,6.2,1.8,2.5,2.3,5.7,6.9,.9,4.4,5.2,1.9,.6,7.4,1.2,6.6,3.3,4.9),nrow=10,ncol=2) #given matrix
p1=c(6,6)
k=3 nn.3=k.nn(k,p1,p)
print(nn.3)
There's a missing carriage return or ";" in the penultimate line that is throwing an error. If you remove tha last line so that you can use traceback() it tells you that k.nn throws a " subscript out of bounds" error when a matrix index is 4.
Debugging 101 tells you to put in print functions to see where the function fails and putting in a print after
c=class(x) ; print(c)
... ives you a result, but putting another one in the sort.d function does not get executed. Looking at the code upstream from that point we see:
d <- sqrt((matrix[,1]-matrix[,3])^2+(matrix[,2]-matrix[,4])^2)
So looking at the function and the matrix you have given, ... my guess is that you passed a two-column matrix to a function that expected a four-column argument.

Resources