Use result of previous loop as input for next loop - r

I have the code below, which seems to accomplish what I'm trying to do but also throws the error output shown below the code. What I'm trying to do, is run through the loop the first time with x = 1, then for each time the loop runs after that I want x = y, the result of the previous loop. I always fumble with loops so any tips are greatly appreciated.
Code:
for(i in 1:5)
{
if(i=1)
{
x<-1
}
else
{
x<-y
}
y<-x*i
y
}
ERRORS:
for(i in 1:5)
+ {
+ if(i=1)
Error: unexpected '=' in:
"{
if(i="
> {
+ x<-1
+ }
> else
Error: unexpected 'else' in " else"
> {
+ x<-y
+ }
> y<-x*i
> y
[1] 25
> }
Error: unexpected '}' in "}"

Here is your code re-written with slightly clearer syntax
for (i in 1:5) {
if (i == 1) {
x <- 1
} else {
x <- y
}
y <- x * i
}
Or even better syntax.
for (i in 1:5) {
x <- ifelse(i == 1, 1, y)
y <- x * i
}

Related

Why can't I use in with an if condition

I have the following code:
x=rnorm(100,0,1)
x
a=0
for(i in x){
if(i in -1:1){
a<-a+1
}
}
I'm getting the following error:
Geeting error unexpected '}' in " }"
What am I doing wrong?
I changed the condition in the if statement. Is this what you want?
x=rnorm(100,0,1)
x
a = 0
for(i in x){
if(i > -1 & i < 1){
a <- a + 1
}
}

How to restart a loop with eval with timeout in R?

while (!exists("j")) {
i <- 1
repeat {
tryCatch(expr = {
print(i)
raw.result <- evalWithTimeout(Sys.sleep(i), timeout = 3)
if (i == 1) {
j <- i
} else {
j <- c(j, i)
}
i <- i + 1
}, TimeoutException = function(ex) {
rm("j")
})
}
}
The above code is getting stuck at i=4 and keeps executing the function for i=4, however I want it to restart from i=1, whenever there is an error.
Can someone please guide on where am I doing it wrong?
In your codeTimeoutException is unable to find j as it is evaluated in a different environment. Even if it was able to find it, nothing would change. As tryCatch is stopping an error from breaking a repeat loop, thus repeat will continue with the current i. You could explicitly break out from the repeat, but in that case you have deleted j, thus your while will stop.
I am not quite sure why you need while loop here.
Here is a modification of your code that will work as you want.
Fist explicitly set i <- 1, and rest it again to i <<-1 (Note <<- as i is one environment above tryCatch).
i <- 1
repeat {
tryCatch(
expr = {
print(i)
raw.result <- R.utils:evalWithTimeout(Sys.sleep(i), timeout = 3)
if (i == 1) {
j <- i
} else {
j <- c(j, i)
}
i <- i + 1
},
TimeoutException = function(ex) {
i <<- 1
}
)
}

KnapSack dynamic programming in R with recursive function

I created this simple code in R to solve the Knapsack program with a recursive funtion
n <- c(0,1,2,3,4)
v <- c(10,40,30,50)
w <- c(5,4,6,3)
k <- 10
myfunction <- function(n,k){
if (n==0 | k==0){
output <- 0
} else if (w[i] > k) {
output <- myfunction[i-1,w]
} else {
output <- max(v[i]+ myfunction(i-1, k-w[i]),myfunction(i-1,k))
}
return(myfunction)
}
However, I don't get a value as an output, but the whole function. For example if I put in:
myfunction(4,10)
I don't get an value of 90, but the whole funtion typed out.
these are the values
There were several errors beyond the ones pointed out by #etienne. Here's an annotated debugging session. First we fix the returned object:
> myfunction <- function(n,k){
+ if (n==0 | k==0){
+ output <- 0
+ } else if (w[i] > k) {
+ output <- myfunction[i-1,w]
+ } else {
+ output <- max(v[i]+ myfunction(i-1, k-w[i]),myfunction(i-1,k))
+ }
+ return(output)
+ }
> myfunction(4,10)
Error in if (w[i] > k) { : argument is of length zero
Obviously neither w nor k are of length zero which suggests it must be i. (As also pointed out by etienne). Looking at your code it appears you actually intended i to be the index that decreased until the terminating condition was met. So replace n by i in the few instances where it appeared:
> myfunction <- function(i,k){
+ if (i==0 | k==0){
+ output <- 0
+ } else if (w[i] > k) {
+ output <- myfunction[i-1,w]
+ } else {
+ output <- max(v[i]+ myfunction(i-1, k-w[i]),myfunction(i-1,k))
+ }
+ return(output)
+ }
> myfunction(4,10)
Error in myfunction[i - 1, w] :
object of type 'closure' is not subsettable
So you also made the mistake of using square-brackets where parentheses (aka bracket in the non-US sections of the world) were needed:
> myfunction <- function(i,k){
+ if (i==0 | k==0){
+ output <- 0
+ } else if (w[i] > k) {
+ output <- myfunction(i-1,w)
+ } else {
+ output <- max(v[i]+ myfunction(i-1, k-w[i]),myfunction(i-1,k))
+ }
+ return(output)
+ }
> myfunction(4,10)
[1] 90
Success, well, almost. Most of the warnings are because you used | instead of || in one of the conditionals:
Warning messages:
1: In if (i == 0 | k == 0) { :
the condition has length > 1 and only the first element will be used
2: In if (w[i] > k) { :
the condition has length > 1 and only the first element will be used
3: In if (i == 0 | k == 0) { :
the condition has length > 1 and only the first element will be used
4: In if (i == 0 | k == 0) { :
the condition has length > 1 and only the first element will be used
5: In if (i == 0 | k == 0) { :
the condition has length > 1 and only the first element will be used
6: In if (i == 0 | k == 0) { :
the condition has length > 1 and only the first element will be used
So replace that instance with a logical ||. To deal with the other warning that didn't seem to sabotage your logic, realize that w[i] is length-0 when i == 0, so add a logical clause in the conditional that first tests for that possibility and use the correct "double-AND-sign" ( && ):
myfunction <- function(i,k){
if (i==0 || k==0){
output <- 0
} else if (length( w[i]) && w[i] > k) {
output <- myfunction(i-1,w)
} else {
output <- max(v[i]+ myfunction(i-1, k-w[i]), myfunction(i-1,k))
}
return(output)
}
Now you get:
> myfunction(4,10)
[1] 90

How to retry a statement on error?

How can I simply tell R to retry a statement a few times if it errors? E.g. I was hoping to do something like:
tryCatch(dbGetQuery(...), # Query database
error = function(e) {
if (is.locking.error(e)) # If database is momentarily locked
retry(times = 3) # retry dbGetQuery(...) 3 more times
else {
# Handle other errors
}
}
)
I usually put the try block in a loop,
and exit the loop when it no longer fails or the maximum number of attempts is reached.
some_function_that_may_fail <- function() {
if( runif(1) < .5 ) stop()
return(1)
}
r <- NULL
attempt <- 1
while( is.null(r) && attempt <= 3 ) {
attempt <- attempt + 1
try(
r <- some_function_that_may_fail()
)
}
I wrote a quick function that allows you to easily retry an operating a configurable number of times, with a configurable wait between attempts:
library(futile.logger)
library(utils)
retry <- function(expr, isError=function(x) "try-error" %in% class(x), maxErrors=5, sleep=0) {
attempts = 0
retval = try(eval(expr))
while (isError(retval)) {
attempts = attempts + 1
if (attempts >= maxErrors) {
msg = sprintf("retry: too many retries [[%s]]", capture.output(str(retval)))
flog.fatal(msg)
stop(msg)
} else {
msg = sprintf("retry: error in attempt %i/%i [[%s]]", attempts, maxErrors,
capture.output(str(retval)))
flog.error(msg)
warning(msg)
}
if (sleep > 0) Sys.sleep(sleep)
retval = try(eval(expr))
}
return(retval)
}
So you can just write val = retry(func_that_might_fail(param1, param2), maxErrors=10, sleep=2) to retry calling that function with those parameters, give up after 10 errors, and sleep 2 seconds between attempts.
Also, you can redefine the meaning of what an error looks like by passing a different function as parameter isError, which by default will catch an error signaled with stop. This is useful if the function being called does something else on error, such as returning FALSE or NULL.
This is the alternative I've found so far that results in clearer, more readable code.
Hope this helps.
A solution without pre-assigning values and using for instead of while:
some_function_that_may_fail <- function(i) {
if( runif(1) < .5 ) stop()
return(i)
}
for(i in 1:10){
try({
r <- some_function_that_may_fail(i)
break #break/exit the for-loop
}, silent = FALSE)
}
r will be equal to the number of tries that were needed. If you dont want the output of the errors set silent to TRUE
Here's a function to generate a custom condition to respond to
locked <- function(message="occurred", ...) {
cond <- simpleCondition(message, ...)
class(cond) <- c("locked", class(cond))
cond
}
and a function implemented to allow (an infinite number of) restarts
f <- function() {
cnt <- 0L
repeat {
again <- FALSE
cnt <- cnt + 1L
withRestarts({
## do work here, and if needed...
signalCondition(locked())
}, retry=function() {
again <<- TRUE
})
if (!again) break
}
cnt
}
and the use of withCallingHandlers (to keep the context where the condition was signaled active unlike tryCatch) to handle the locked condition
withCallingHandlers({
n_tries <- 0L
f()
}, locked=function(e) {
n_tries <<- n_tries + 1L
if (n_retries < 3)
invokeRestart("retry")
})
I have put together the code and make it package: retry
f <- function(x) {
if (runif(1) < 0.9) {
stop("random error")
}
x + 1
}
# keep retring when there is a random error
retry::retry(f(1), when = "random error")
#> [1] 2
# keep retring until a requirement is satisified.
retry::retry(f(1), until = function(val, cnd) val == 2)
#> [1] 2
# or using one sided formula
retry::retry(f(1), until = ~ . == 2, max_tries = 10)
#> [1] 2
I like setting my object as an error from the start, also sometimes useful to add some sleep time if you're having connection problems:
res <- simpleError("Fake error to start")
counter <- 1
max_tries <- 10
# Sys.sleep(2*counter)
while(inherits(res, "error") & counter < max_tries) {
res <- tryCatch({ your_fun(...) },
error = function(e) e)
counter <- counter + 1
}

for loop with if else statement in R

I know lots of people have posted about this, and I did look through the answers to write my code, but it's still not working... Can someone point out where i'm doing wrong please? many thanks in advance!
for(j in 1:1000){
for(i in 1:52){
if (i == 1){
r.sims[i,] <- r.sims[1]
}
else if (i == 2){
r.sims[i,] <- r.sims[2]
}
else (i > 2){
r.sims[i,] <- r.sims[i-1,]*ar1 + r.sims[i-2,]*ar2 + e.sims[i,] + e.sims[i-1,]*ma1
}
}
}
i have the following errors
Error: unexpected '{' in:
" }
else (i > 2){"
> r.sims[i,] <- r.sims[i-1,]*ar1 + r.sims[i-2,]*ar2 + e.sims[i,] + e.sims[i-1,]*ma1
Error in r.sims[i, ] <- r.sims[i - 1, ] * ar1 + r.sims[i - 2, ] * ar2 + :
replacement has length zero
> }
Error: unexpected '}' in " }"
>
> }
Error: unexpected '}' in " }"
>
> }
Error: unexpected '}' in " }"
>
Without understanding what your code is supposed to do, I have nevertheless made an example of how you might fix your script. I think the key is that you need to supply curly brackets {...} following your else statement in order for it to consider the following code.
Example:
r.sims <- matrix(runif(52)*100, nrow=52, ncol=100)
e.sims <- matrix(runif(52)*100, nrow=52, ncol=100)
ma1 <- 1
ar1 <- 2
ar2 <- 3
for(j in 1:1000) {
for(i in 1:52) {
if (i == 1) {
r.sims[i,] <- r.sims[1]
} else {
if(i == 2) {
r.sims[i,] <- r.sims[2]
} else {
if(i > 2) {
r.sims[i,] <- r.sims[i-1,]*ar1 + r.sims[i-2,]*ar2 + e.sims[i,] + e.sims[i-1,]*ma1
}
}
}
}
}
You seem to misunderstand the concept of else.
else covers all cases that didn't match previous if or else if statements.
Therefore, you cannot specify any condition for else.
To cover all cases where i is not 1 or 2 simply use else, without any () brackets.
If you want to have a condition, use else if (condition).

Resources