Reputation: 473
I have R code that sometimes returns an NA
, which causes errors downstream. However, the only reason that it fails stems from a bad random number. Run the expression again with a different starting point, and it produces results that are not NA
.
I've setup a while
loop to try the expression multiple times before giving up. Here's an example:
attempts <- 0
x <- NA
while(is.na(x) & attempts < 100) {
attempts <- attempts + 1
rand <- runif(1)
x <- ifelse(rand > 0.3, rand, NA)
}
if(attempts == 100) stop("My R code failed")
x
I don't like how clunky this is.
Is there a function, package, or method that can help simplify this try-repeat-try-again expression?
Upvotes: 1
Views: 1768
Reputation: 1275
I had some success doing something similar with the retry
package, which has the functionality to repeatedly run code until some condition is met.
https://cran.r-project.org/package=retry
My situation was a little different from yours in that my code for generating/sending emails would fail periodically, and so I wanted to rerun it until the return condition wasn't NULL.
retry::retry({
# original code to compose an email,
# add some attachments and then send
},
until = \(val, condition) { is.null(condition) },
max_tries = 10)
I imagine if you change the until
function, you could test for the return value e.g.
until = \(val, condition) { !is.na(val) }
Upvotes: 0
Reputation: 269694
1) We could turn it into a function which returns x
if it finds one or stops if not. Also we use for
instead of while
and if
instead of ifelse
.
retry <- function() {
for(i in 1:100) {
rand <- runif(1)
x <- if (rand > 0.3) rand else NA
if (!is.na(x)) return(x)
}
stop("x is NA")
}
retry()
2) or if you don't want the stop in the function then remove the stop
line replacing it with a line that returns x and then use this (although it does involve testing x for NA twice):
x <- retry()
if (is.na(x)) stop("x is NA")
3) or another option is to pass the bad value to the function. Because of lazy evaluation the bad
argument is only evaluated if it is, in fact, bad:
retry2 <- function(bad) {
for(i in 1:100) {
rand <- runif(1)
x <- if (rand > 0.3) rand else NA
if (!is.na(x)) return(x)
}
bad
}
retry2(stop("x is NA"))
4) If you don't mind testing x for NA twice using break
also works even without a function:
for(i in 1:100) {
rand <- runif(1)
x <- if (rand > 0.3) rand else NA
if (!is.na(x)) break
}
if (is.na(x)) stop("x is NA")
x
Upvotes: 2