I have a regression model (lm
or glm
or lmer
...) and I do fitmodel <- lm(inputs)
where inputs
changes inside a loop (the formula and the data). Then, if the model function does not produce any warning I want to keep fitmodel
, but if I get a warning I want to update
the model and I want the warning not printed, so I do fitmodel <- lm(inputs)
inside tryCatch
. So, if it produces a warning, inside warning = function(w){f(fitmodel)}
, f(fitmodel)
would be something like
fitmodel <- update(fitmodel, something suitable to do on the model)
In fact, this assignation would be inside an if-else
structure in such a way that depending on the warning if(w$message satisfies something)
I would adapt the suitable to do on the model
inside update
.
The problem is that I get Error in ... object 'fitmodel' not found
. If I use withCallingHandlers
with invokeRestarts
, it just finishes the computation of the model with the warning without update
it. If I add again fitmodel <- lm(inputs)
inside something suitable to do on the model
, I get the warning printed; now I think I could try suppresswarnings(fitmodel <- lm(inputs))
, but yet I think it is not an elegant solution, since I have to add 2 times the line fitmodel <- lm(inputs)
, making 2 times all the computation (inside expr
and inside warning
).
Summarising, what I would like but fails is:
tryCatch(expr = {fitmodel <- lm(inputs)},
warning = function(w) {if (w$message satisfies something) {
fitmodel <- update(fitmodel, something suitable to do on the model)
} else if (w$message satisfies something2){
fitmodel <- update(fitmodel, something2 suitable to do on the model)
}
}
)
What can I do?
The loop part of the question is because I thought it like follows (maybe is another question, but for the moment I leave it here): it can happen that after the update
I get another warning, so I would do something like while(get a warning on update){update}
; in some way, this update
inside warning
should be understood also as expr
. Is something like this possible?
Thank you very much!
Generic version of the question with minimal example:
Let's say I have a tryCatch(expr = {result <- operations}, warning = function(w){f(...)}
and if I get a warning in expr
(produced in fact in operations
) I want to do something with result
, so I would do warning = function(w){f(result)}
, but then I get Error in ... object 'result' not found
.
A minimal example:
y <- "a"
tryCatch(expr = {x <- as.numeric(y)},
warning = function(w) {print(x)})
Error in ... object 'x' not found
I tried using withCallingHandlers
instead of tryCatch
without success, and also using invokeRestart
but it does the expression part, not what I want to do when I get a warning.
Could you help me?
Thank you!
The problem, fundamentally, is that the handler is called before the assignment happens. And even if that weren’t the case, the handler runs in a different scope than the tryCatch
expression, so the handler can’t access the names in the other scope.
We need to separate the handling from the value transformation.
For errors (but not warnings), base R provides the function try
, which wraps tryCatch
to achieve this effect. However, using try
is discouraged, because its return type is unsound.1 As mentioned in the answer by ekoam, ‘purrr’ provides soundly typed functional wrappers (e.g. safely
) to achieve a similar effect.
However, we can also build our own, which might be a better fit in this situation:
with_warning = function (expr) {
self = environment()
warning = NULL
result = withCallingHandlers(expr, warning = function (w) {
self$warning = w
tryInvokeRestart('muffleWarning')
})
list(result = result, warning = warning)
}
This gives us a wrapper that distinguishes between the result value and a warning. We can now use it to implement your requirement:
fitmodel = with(with_warning(lm(inputs)), {
if (! is.null(warning)) {
if (conditionMessage(warning) satisfies something) {
update(result, something suitable to do on the model)
} else {
update(result, something2 suitable to do on the model)
}
} else {
result
}
})
1 What this means is that try
’s return type doesn’t distinguish between an error and a non-error value of type try-error
. This is a real situation that can occur, for example, when nesting multiple try
calls.