I have a function that conditionally prints messages/warnings, e.g. like below:
test <- function(x)
{
for (i in 1:5)
{
if (i == 3)
{
warning("test")
break()
}
if (i != 3)
{
message(i)
}
}
}
The function correctly breaks out of index 3 and prints the warning.
test(1)
1
2
Warning message:
test
However, when I wrap that function into an lapply, the warning message is only printed at the end:
lapply(1:2, test)
1
2
1
2
[[1]]
NULL
[[2]]
NULL
Warning messages:
1: In FUN(X[[i]], ...) : test
2: In FUN(X[[i]], ...) : test
How can I make sure that the message is printed "per loop"? I.e.
1
2
Warning messages:
1: In FUN(X[[i]], ...) : test
1
2
Warning messages:
1: In FUN(X[[i]], ...) : test
[[1]]
NULL
[[2]]
NULL
You can set immediate warnings globally using options(warn = 1). warning() also has an immediate. argument for specific use:
test <- function(x)
{
for (i in 1:5)
{
if (i == 3)
{
warning("test", immediate. = TRUE)
break()
}
if (i != 3)
{
message(i)
}
}
}
lapply(1:2, test)
1
2
Warning in FUN(X[[i]], ...) : test
1
2
Warning in FUN(X[[i]], ...) : test
[[1]]
NULL
[[2]]
NULL
Note from the documentation:
warning signals a warning condition by (effectively) calling
signalCondition. If there are no handlers or if all handlers return,
then the value of warn = getOption("warn") is used to determine the
appropriate action. If warn is negative warnings are ignored; if it is
zero they are stored and printed after the top–level function has
completed; if it is one they are printed as they occur and if it is 2
(or larger) warnings are turned into errors. Calling
warning(immediate. = TRUE) turns warn <= 0 into warn = 1 for this call
only.
Related
I am new to R and I have checked most links online but I have not been able to solve the problem.
Here is a reproducible example of a Monte Carlo simulation I am doing:
rm(list = ls())
x=c(-2,3,-1,4,'A')
y=rep(0,5)
for(i in 1:5){
tryCatch(
expr = {
y[i]=log(x[i])
},
error = function(e){
message('Caught an error!',i)
return(NA)
},
warning = function(w){
message('Caught an warning!',i)
return(NA)
}
)
}
Please how do I fix the code so that at the end of the for loop, R returns the values of y as
y= NA,log(3),NA,log(4),NA
i=1,3,5
and the values of i where there was an error or warning.
That is, error and warnings are replaced with NA and successful evaluations are returned and the values of i where there was an error or warning are also returned.
Thanks
Initialise y with NA and then run the for loop. Also since x is a vector and vector can hold only one class all the numbers in x turn to characters as you have non-numeric elements in x so you need to convert them to numbers before taking log.
x=c(-2,3,-1,4,'A')
y=rep(NA,5)
for(i in 1:5){
tryCatch(
expr = {
y[i]= log(as.numeric(x[i]))
},
error = function(e){
message('Caught an error!',i)
},
warning = function(w){
message('Caught a warning! ',i)
}
)
}
#Caught a warning! 1
#Caught a warning! 3
#Caught a warning! 5
y
#[1] NA 1.098612 NA 1.386294 NA
and then use is.na with which to get the index where error or warning happened.
which(is.na(y))
#[1] 1 3 5
Of course, you can do this without for loop as well
y <- log(as.numeric(x))
which(is.na(y))
#[1] 1 3 5
To return different value based on error or warning, we can make this into a function
run_fun <- function(x) {
tryCatch(
expr = {
return(log(as.numeric(x)))
},
error = function(e){
message('Caught an error!',i)
return(100)
},
warning = function(w){
message('Caught a warning! ',i)
return(200)
}
)
}
and then call it in for loop.
for (i in seq_along(x)) {
y[i] <- run_fun(x[i])
}
y
#[1] 200.0000 1.0986 200.0000 1.3863 200.0000
I called other lib function, which does the calculation and throws warning message. I tried to use tryCatch() to capture the message but do not know how to keep the calculated value and the warning message. Here is sample (simplified) code, I would like mydiv function has both calculated value and warning message. Right now mydiv calls will return the division value or the warning but not both.
mydiv = function(x, y){
tryCatch({
# raise warning message
if (x > y)
warning("throw a warning")
# function calc result
x/y
},
warning = function(war) {
flag = paste("DIV Warning:", war$message)
return (flag)
},
error = function(err) {
flag = paste("DIV Err", err)
return (flag)
})
}
If I call x = mydiv(2, 1) then the x has value "DIV Warning: throw a warning"; if x = mydiv(2, 4) then x: [1] 0.5.
So my question is: 1. use tryCatch: how to return the calculated value and warning message if possible; 2. whether there is a better approach to get both values from a function.
You could use the built in warning function as in the following:
mydiv = function(x, y){
if (x > y)
warning("throw a warning")
# function calc result
return(x/y)
}
If you want to return a warning instead of emitting it as a warning message, you could return a named list, where the warning entry in the list will be NA if no warning is generated:
mydiv = function(x, y){
warn <- NA
if (x > y)
warn <- "throw a warning"
# function calc result
return(list(value=x/y, warning=warn))
}
I am trying to write an error exception handling in R using tryCatch.
correct = 1
tryCatch({
sqrt(b)
},
warning = function(w){
print("NaNs")
},
finally = {
correct = 0
}
)
correct
If I set b = -5, the warning is printed and the value of correct is 0. If I set b = 5, the warning is not printed. However the value is still 0. What I would like is that when there is some warning/error to catch, the value of correct is 0. When there is no warning/error, the value of correct is 1. Thanks!
You don't want finally here. Instead just specify return values of 0 when an error or warning occurs.
myfun <- function(b) {
tryCatch({
sqrt(b)
},
error = function(e){
return(0)
},
warning = function(w){
return(0)
}
)
}
> myfun(5)
# [1] 2.236068
> myfun(-5)
# [1] 0
Here is a function:
is.bad <- function(x) {
as.numeric(isTRUE(tryCatch(x,
error = function(c) TRUE,
warning = function(c) TRUE
)))
}
is.bad(stop())
is.bad(warning())
is.bad(message())
is.bad(3)
## > is.bad(stop())
## [1] 1
## > is.bad(warning())
## [1] 1
## > is.bad(message())
##
## [1] 0
## > is.bad(3)
## [1] 0
The finally clause is executed regardless of whether or not a warning is thrown in the square root. That's why you end up with correct == 0 regardless.
The following code will do what you want, although I used a global assignment <<- which might cause problems if you are not careful. This was necessary because otherwise you can't change the value of correct from within the warning function.
correct = 1
tryCatch({
sqrt(b)
},
warning = function(w){
print("NaNs")
correct <<- 0
}
)
With mclapply() all issued warnings seems get suppressed:
library(multicore)
mclapply(1:3, function(x) warning(x))
[[1]]
[1] "1"
[[2]]
[1] "2"
[[3]]
[1] "3"
while lapply would give:
lapply(1:3, function(x) warning(x))
[[1]]
[1] "1"
[[2]]
[1] "2"
[[3]]
[1] "3"
Warning messages:
1: In FUN(1:3[[3L]], ...) : 1
2: In FUN(1:3[[3L]], ...) : 2
3: In FUN(1:3[[3L]], ...) : 3
Any tips on how to avoid loosing the warnings?
According to mclapply's help page, in my opinion the argument mc.silent should allow you to chose if warnings are to be printed or not. Strangely, it does not do that. Setting it explictly to TRUE or FALSE does not have any effect in your situation.
So that leaves us only with a somewhat dirty hack: forcing R to print warnings as they occur.
options(warn=1)
mclapply(1:3, function(x) warning(x))
# Warning in FUN(1L[[1L]], ...) : 1
# Warning in FUN(2L[[1L]], ...) : 2
# Warning in FUN(3L[[1L]], ...) : 3
# [[1]]
# [1] "1"
#
# [[2]]
# [1] "2"
#
# [[3]]
# [1] "3"
I have this problem too. If I'm reading the code correctly, parallel::mclapply() passes the mc.silent option to parallel:mcparallel(). But mcparallel() has this line:
sendMaster(try(eval(expr, env), silent = TRUE))
I think that's the place where the warnings would be sent back to the master process, but the mc.silent is not respected. That's my best guess about what is going on.
For anyone who will come around the same issue, here is a workaround:
safe_mclapply <- function(X, FUN, mc.cores, stop.on.error=T, ...){
fun <- function(x){
res_inner <- tryCatch({
withCallingHandlers(
expr = {
FUN(x, ...)
},
warning = function(e) {
message_parallel(trimws(paste0("WARNING [element ", x,"]: ", e)))
# this line is required to continue FUN execution after the warning
invokeRestart("muffleWarning")
},
error = function(e) {
message_parallel(trimws(paste0("ERROR [element ", x,"]: ", e)))
}
)},
error = function(e){
# error is returned gracefully; other results of this core won't be affected
return(e)
}
)
return(res_inner)
}
res <- mclapply(X, fun, mc.cores=mc.cores)
failed <- sapply(res, inherits, what = "error")
if (any(failed == T)){
error_indices <- paste0(which(failed == T), collapse=", ")
error_traces <- paste0(lapply(res[which(failed == T)], function(x) x$message), collapse="\n\n")
error_message <- sprintf("Elements with following indices failed with an error: %s. Error messages: \n\n%s",
error_indices,
error_traces)
if (stop.on.error)
stop(error_message)
else
warning(error_message, "\n\n### Errors will be ignored ###")
}
return(res[!failed])
}
#' Function which prints a message using shell echo; useful for printing messages from inside mclapply when running in Rstudio
message_parallel <- function(...){
system(sprintf('echo "\n%s\n"', paste0(..., collapse="")))
}
safe_mclapply above is a wrapper around mclapply. For each iteration it uses withCallingHandlers to catch and print warnings and errors; note that invokeRestart("muffleWarning") is required in order to continue FUN exection and return the result. Printing is done via message_parallel function which uses shell echo to print messages to R console (tested to work in Rstudio).
safe_mclapply provides few more features which you might find optional:
along with the warning and error it prints character representation of x which I find useful because it gives an idea where the message comes from
tryCatch around withCallingHandlers helps to return an error gracefully so that other results of the core are not affected
after mclapply is executed, the indices of error results are printed
stop.on.error provides an option to ignore any results which contain error and continue despite the errors
Side note: I personally prefer pbmclapply function from pbmcapply over mclapply which adds a progress bar. You can change mclapply to pbmclapply in the code above.
Small snippet to test the code:
X <- list(1, 2, 3, 4, 5, 6)
f <- function(x){
if (x == 3){
warning("a warning")
warning("second warning")
}
if (x == 6){
stop("an error")
}
return(x + 1)
}
res <- safe_mclapply(X = X, FUN = f, mc.cores=16)
res_no_stop <- safe_mclapply(X = X, FUN = f, mc.cores=16, stop.on.error = F)
op <- options(warn=0) #although doesn't work for any value of warn
assign("last.warning", NULL, envir = baseenv())
thisDoesntWork<- function() {
warning("HEY, this is definitely a warning!")
cat(paste("number of warnings:",length(warnings())))
}
>thisDoesntWork()
Warning in thisDoesntWork() : HEY, this is definitely a warning!
number of warnings: 0
Number of warnings should be 1 rather than 0 -
it seems that warnings() returns nothing if called within a function. Why? How can one work around this to check within a function if warnings occurred, and print them out?
I don't want to use tryCatch, because then I lose the value that the function returns (it may still return a valid value, even if it generated a warning).
Here's the code for suppressWarnings
function (expr)
{
withCallingHandlers(expr, warning = function(w) invokeRestart("muffleWarning"))
}
I've tweaked it a little to count the number of warnings instead.
countWarnings <- function(expr)
{
.number_of_warnings <- 0L
frame_number <- sys.nframe()
ans <- withCallingHandlers(expr, warning = function(w)
{
assign(".number_of_warnings", .number_of_warnings + 1L,
envir = sys.frame(frame_number))
invokeRestart("muffleWarning")
})
message(paste("No. of warnings thrown:", .number_of_warnings))
ans
}
A test:
countWarnings(log(-1))
No. of warnings thrown: 1
[1] NaN
Another test:
foo <- function()
{
warning("first warning!")
warning("second warning!")
warning("third warning!")
invisible()
}
countWarnings(foo())
No. of warnings thrown: 3
NULL
Your example does return a warning.
> assign("last.warning", NULL, envir = baseenv())
> thisDoesntWork <- function() {
+ warning("HEY, this is definitely a warning!")
+ cat(paste("number of warnings:",length(warnings())),"\n")
+ }
> thisDoesntWork()
number of warnings: 0
Warning message:
In thisDoesntWork() : HEY, this is definitely a warning!
> warnings() # HEY, here's your warning!!!
Warning message:
In thisDoesntWork() : HEY, this is definitely a warning!
The documentation isn't explicit, but I don't think last.warning gets set until the call finishes (especially given the call is part of what can be returned).
probably this is a very very bad workaround...
fw<-function(){warning("warn...");return(99)}
fn<-function(){return(88)}
f<-function(){
w<-0
v<-NULL
v<-tryCatch(fw(),warning=function(w){w})
if("warning"%in%class(v)){
w<-w+1 # e.g., count up the number of warning
v<-fw()
}
print(v)
v<-NULL
v<-tryCatch(fn(),warning=function(w){w})
if("warning"%in%class(v)){
w<-w+1 # e.g., count up the number of warning
v<-fn()
}
print(v)
}
f()
calling the function twice if warning occurs...
though I believe that there must be more elegant solutions
Here is a workaround
..my_warning <- 0L
thisDoesWork<- function(){
assign("last.warning", NULL, envir = baseenv())
warning("HEY, this is definitely a warning!", {..my_warning <<- ..my_warning+1L;""})
str(last.warning)
cat(paste("number of warnings:", ..my_warning, "\n"))
}
thisDoesWork()
Warning in thisDoesWork() : HEY, this is definitely a warning!
NULL
number of warnings: 1
> thisDoesWork()
Warning in thisDoesWork() : HEY, this is definitely a warning!
NULL
number of warnings: 2
> thisDoesWork()
Warning in thisDoesWork() : HEY, this is definitely a warning!
NULL
number of warnings: 3
>
The warnings are issued not before the function returns.
See the documentation for options("warn"):
options(warn=1L)
thisDoesntWork()
#Warning in thisDoesntWork() : HEY, this is definitely a warning!
#number of warnings: 1