Reputation: 8791
I have a function that I'm applying to a matrix. But the vector is to extensive and I'd like to check the progress of it with a counter.
N = 10
j = 0
functionX <- function(a,b,c) {
... stuff here ...
j<- j+1
print(paste(j/N,'%'))
}
a <- mapply(functionX, a[1:10,1],b[1:10,2],c[1:10,3])
But this approach is not working, because j never gets bigger than 1 with mapply, and I would like to avoid for loops.
Upvotes: 4
Views: 965
Reputation: 46876
It's never a good idea to write to the global environment, so use a function that returns a function.
counter = function(FUN, report=10) {
j <- 0L # initialize the counter
function(...) { # a function that takes '...' and...
j <<- j + 1L # increment j in a containing env
if ((j %% report) == 0L)
message(j)
FUN(...) # ...passes all args '...' to FUN
}
}
The line j <<- j + 1
says that, for the assignment, look first in the environment in which the function was defined, rather than in the function itself. The line j <- 0L
servers as a kind of break in where <<-
looks for j -- it finds and updates it in this environment. If j
were not found, then the <<-
operator would continuing looking for a symbol in the defining environment until arriving at the global environment.
In action:
> x = sapply(1:20, counter(c, 5)) # concatenate elements c()
5
10
15
20
> x
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
> countedc = counter(c)
> x = integer(); for (i in 1:12) x = countedc(x, i)
10
> for (i in 1:9) x = countedc(x, i)
20
> x
[1] 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9
One might also use ?txtProgressBar
. There may be problems if FUN
uses 'non-standard evaluation' for its arguments as, e.g., subset()
does.
It's rare for matrix operations to take a long time; maybe you are iterating but should be using vectorized calculations?
Notice that any global variable I'd defined and named j
would be unchanged
> j <- 42 # Yes! the meaning of life. Don't lose this!
> countedc(x, 0)
[1] 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 0
> j # Would have been clobbered if counter used global env
[1] 42
Upvotes: 2
Reputation: 57220
The problem is inside functionX
you're assigning a value to j
and so your also defining a new j
variable that exists only in the function environment and is different from the j
defined outside of functionX
.
If you want to change the outside j
you can do:
j <<- j+1
however it's preferable to not modify variables in a parent environment, so I suggest you to pass a new variable to mapply representing the iteration counter e.g. :
N = 10
functionX <- function(iteration,a,b,c) {
# elaboration here
print(paste( (iteration/N) * 100,'%'))
}
a <- mapply(functionX, 1:10, a[1:10,1],b[1:10,2],c[1:10,3])
Upvotes: 4