How to print progress bar of R function without for loop? - r

I have a function that takes a long time to run (involves many calculations in a large dataset). I want to include a progress bar to see if it's making progress. My function has no for loops; I don't understand how to add a progress bar if I don't have a for loop in the function.
I tried adding a for loop to get the progress bar to work, but it's just printing the progress bar without doing the calculations (I believe), i.e. when I print result I get NULL:
install.packages("svMisc")
require("svMisc")
# Test function
funct<-function(a,b,c)for (i in 0:101){
progress(i, progress.bar=TRUE)
Sys.sleep(0.01)
x<-a*a
y<-x+b
z<-y/2
if (i == 101) message("Done!")
}
result <- funct(-2.6e+70,-2.5e+121,6)
result
Feel free to suggest something other than svMisc.

In general, reporting the progress of a function will require a loop (or possibly a number of lines of code), as you've set out in your example. Your example is performing the calculations, it is just not returning them - remember that R functions return the value of the last calculation unless there is an explicit return() statement. In this case, the message() function returns NULL.
The minor modification to your code below demonstrates the expected behaviour of the progress bar, followed by result having the calculated value.
install.packages("svMisc")
require("svMisc")
# Test function
funct<-function(a,b,c){
for (i in 0:101){
progress(i, progress.bar=TRUE)
Sys.sleep(0.01)
x<-a*a
y<-x+b
z<-y/2
if (i == 101) message("Done!")
}
return(z)
}
result <- funct(-2.6e+70,-2.5e+121,6)
# 0%---------25%---------50%---------75%--------100%
# Progress: ||||||||||||||||||||||||||||||||||||||||||||||||||
# Done!
result
# [1] 3.38e+140

Related

Manually interrupt a loop in R and continue below

I have a loop in R that does very time-consuming calculations. I can set a max-iterations variable to make sure it doesn't continue forever (e.g. if it is not converging), and gracefully return meaningful output.
But sometimes the iterations could be stopped way before max-iterations is reached. Anyone who has an idea about how to give the user the opportunity to interrupt a loop - without having to wait for user input after each iteration? Preferably something that works in RStudio on all platforms.
I cannot find a function that listens for keystrokes or similar user input without halting until something is done by the user. Another solution would be to listen for a global variable change. But I don't see how I could change such a variable value when a script is running.
The best idea I can come up with is to make another script that creates a file that the first script checks for the existence of, and then breaks if it is there. But that is indeed an ugly hack.
Inspired by Edo's reply, here is an example of what I want to do:
test.it<-function(t) {
a <- 0
for(i in 1:10){
a <- a + 1
Sys.sleep(t)
}
print(a)
}
test.it(1)
As you see, when I interrupt by hitting the read button in RStudio, I break out of the whole function, not just the loop.
Also inspired by Edo's response I discovered the withRestarts function, but I don't think it catches interrupts.
I tried to create a loop as you described it.
a <- 0
for(i in 1:10){
a <- a + 1
Sys.sleep(1)
if(i == 5) break
}
print(a)
If you let it go till the end, a will be equal to 5, because of the break.
If you stop it manually by clicking on the STOP SIGN on the Rstudio Console, you get a lower number.
So it actually works as you would like.
If you want a better answer, you should post a reproducible example of your code.
EDIT
Based on the edit you posted... Try with this.
It's a trycatch solution that returns the last available a value
test_it <- function(t) {
a <- 0
tryCatch(
for(i in 1:10){
a <- a + 1
message("I'm at ", i)
Sys.sleep(t)
if(i==5) break
},
interrupt = function(e){a}
)
a
}
test_it(1)
If you stop it by clicking the Stop Sign, it returns the last value a is equal to.

R: I have a function with an invisible return value, how can I vectorize it and not get a huge null output?

I have written a fairly simple function, that I believe returns nothing:
bar<-function(a,b)
{
if(foo(a,b)){print(c(a,b))}
return(invisible())
}
I want to call this function on a huge matrix, for example, outer(1:100,1:100,Vectorize(bar)). When doing so, I get the printing that I desire, but I also get an output of a huge array of NULL values. How can I adapt this code to get rid of the huge array of NULLs and not lose the printing that I want?
This happens as you are invoking a side effect within bar() and then jumping up to the top level. The function bar() completes the side effect (printing) then returns the last value in the final command to the top level.
This arrangement returns a single NULL regardless of the sizes of a and b. As in...
a <- matrix(1:9,nrow=3,ncol=3)
b <- matrix(1:9,nrow=3,ncol=3,byrow=TRUE)
foo <- function(a,b) {
exists("a")
exists("b")
}
bar <- function(a,b) {
if(foo(a,b)) {print(c(a,b))}
NULL # or equivalently: return()
}
x <- bar(a,b) # x will be a single NULL
Alternatively, you could simply do whatever it is in bar() that you want done, return a and b appropriately and then print outside the function using the returned values. In most cases, this would likely be a better idea. Also the "<<-" operator can be used helpfully here, though global vars have their own issues apart from the side effect here.

Output the min value for an argument that doesn't crash an R function

Background:
Suppose an R function crashes due to a numerically ill-defined argument. I want to catch that crash using inherit(). Then, try to use a (perhaps) while() loop where I keep changing the input value until the crash doesn't happen! Finally, I want to know what that value was !
Example:
Suppose a user inputs -5 and my function (below) will crash. But after a crash occurs could my function silently evaluate what the minimum value that would not cause it to crash, is?
foo <- function(input) {
integrate(function(x) qt(.025, x), input, 1e3)[[1]]
}
# Example of crash:
foo(-5)

T test failed in R

Iam using R to run a large number using input from a delimited table which is compost of 40000 row and 4 col. iam trying to implement the t test ,p value , but i have error which is (the data are essentially constant) , i used the for loop and apply for both case i had same issue the code is:
NormData3= NormData1[1:40000,1:5]
for(i in 1:nrow(NormData3)) {
g1=NormData3[i,2:3]
g2=NormData3[i,4:5]
p[i]=t.test(g1,g2,var.equal=TRUE)$p.value
}
I don't know what is the problem ??
It's nice that the software recognizes situations in which a sensible
answer can't be computed. At that point, there are two possible actions:
(1) stop with an informative error, and (2) silently return NA.
If you are running this in a iterative loop, you want the second output. Here is the small function for that :
my.t.test.p.value <- function(...) {
obj<-try(t.test(...), silent=TRUE)
if (is(obj, "try-error")) return(NA) else return(obj$p.value)
}
Use this function instead of t.test in your code. This will not disturb your loop and allows it to continue.

FOR loops giving no result or error in R

I am running the following code:
disc<-for (i in 1:33) {
m=n[i]
xbar<-sum(data[i,],na.rm=TRUE)/m
Sx <- sqrt(sum((data[i,]-xbar)^2,na.rm=TRUE)/(m-1))
Sx
i=i+1}
Running it:
>disc
NULL
Why is it giving me NULL?
This is from the documentation for for, accessible via ?`for`:
‘for’, ‘while’ and ‘repeat’ return ‘NULL’ invisibly.
Perhaps you are looking for something along the following lines:
library(plyr)
disc <- llply(1:33, function(i) {
m=n[i]
xbar<-sum(data[i,],na.rm=TRUE)/m
Sx <- sqrt(sum((data[i,]-xbar)^2,na.rm=TRUE)/(m-1))
Sx
})
Other variants exists -- the ll in llply stands for "list in, list out". Perhaps your intended final result is a data frame or an array -- appropriate functions exist.
The code above is a plain transformation of your example. We might be able to do better by splitting data right away and forgetting the otherwise useless count variable i (untested, as you have provided no data):
disc <- daply(cbind(data, n=n), .(), function(data.i) {
m=data.i$n
xbar<-sum(data.i,na.rm=TRUE)/m
sqrt(sum((data.i-xbar)^2,na.rm=TRUE)/(m-1))
})
See also the plyr website for more information.
Related (if not a duplicate): R - How to turn a loop to a function in R
krlmlr's answer shows you how to fix your code, but to explain your original problem in more abstract terms: A for loop allows you to run the same piece of code multiple times, but it doesn't store the results of running that code for you- you have to do that yourself.
Your current code only really assigns a single value, Sx, for each run of the for loop. On the next run, a new value is put into the Sx variable, so you lose all the previous values. At the end, you'll just end up with whatever the value of Sx was on the last run through the loop.
To save the results of a for loop, you generally need to add them to a vector as you go through, e.g.
# Create the empty results vector outside the loop
results = numeric(0)
for (i in 1:10) {
current_result = 3 + i
results = c(results, current_result)
}
In R for can't return a value. The unique manner to return a value is within a function. So the solution here, is to wrap your loop within a function. For example:
getSx <- function(){
Sx <- 0
disc <- for (i in 1:33) {
m=n[i]
xbar <- sum(data[i,],na.rm=TRUE)/m
Sx <- sqrt(sum((data[i,]-xbar)^2,na.rm=TRUE)/(m-1))
}
Sx
}
Then you call it:
getSx()
Of course you can avoid the side effect of using a for by lapply or by giving a vectorized But this is another problem: You should maybe give a reproducible example and explain a little bit what do you try to compute.

Resources