Up front, you are suffering from the 2nd circle of R's Inferno (https://www.burns-stat.com/pages/Tutor/R_inferno.pdf): growing objects. Each time you call rbind, it makes a complete copy of the frame, does the r-binding, then overwrites that complete copy over the original variable name. So while it might work without noticeable slow-down for the first few dozen, it will slow down a bit over 100 or so ... and you're doing it 56,980 times.
It is generally much better to process things into a list and then do the rbind once at the end on the entire list, as in do.call(rbind, list_of_frames). Granted, you still may have the computational challenge of doing something potentially hard ... luckily zoo is about as efficient as you can get for window operations, and this one is not impossibly hard.
I'll demonstrate on a significantly-reduced problem set (since I don't think it matters if we're looking at 16M or 1.5M iterations.
my.array <- array(1:1502200, dim=c(290,259,5,4))
eg <- do.call(expand.grid, lapply(dim(my.array)[-1], seq_len))
dim(eg)
# [1] 5180 3
head(eg)
# Var1 Var2 Var3
# 1 1 1 1
# 2 2 1 1
# 3 3 1 1
# 4 4 1 1
# 5 5 1 1
# 6 6 1 1
system.time({
list_of_frames <- Map(function(i,j,k) {
u <- zoo::rollapply(my.array[,i,j,k], 2, mean)
data.frame(i, j, k, wind = u)
}, eg[[1]], eg[[2]], eg[[3]])
})
# user system elapsed
# 5.79 0.00 5.80
head(list_of_frames[[5]])
# i j k wind
# 1 5 1 1 1161.5
# 2 5 1 1 1162.5
# 3 5 1 1 1163.5
# 4 5 1 1 1164.5
# 5 5 1 1 1165.5
# 6 5 1 1 1166.5
system.time({
out <- do.call(rbind, list_of_frames)
})
# user system elapsed
# 0.50 0.03 0.53
nrow(out)
# [1] 1497020
rbind(head(out), tail(out))
# i j k wind
# 1 1 1 1 1.5
# 2 1 1 1 2.5
# 3 1 1 1 3.5
# 4 1 1 1 4.5
# 5 1 1 1 5.5
# 6 1 1 1 6.5
# 1497015 259 5 4 1502194.5
# 1497016 259 5 4 1502195.5
# 1497017 259 5 4 1502196.5
# 1497018 259 5 4 1502197.5
# 1497019 259 5 4 1502198.5
# 1497020 259 5 4 1502199.5
Explanation:
do.call(expand.grid, ...) is creating a frame of all the i,j,k combinations you need, dynamically on the dimensions of your array.
Map(f, is, js, ks) runs the function f with the 1st argument of each of is, js, and ks (notional for this bullet), so Map looks something like:
f(is[1], js[1], ks[1])
f(is[2], js[2], ks[2])
f(is[3], js[3], ks[3])
# ...
then we combine them in one call using do.call(rbind, ...). We really have to use do.call here because this call is analogous to
rbind(list_of_frames[[1]], list_of_frames[[2]], ..., list_of_frames[[5180]])
(over to you if you'd prefer to write out this version).
rbind, it is copying the entire frame into a new object and over-writingdf2. It might work for a few dozen, but (as you can see) this scales horribly.something <- lapply(list_of_stuff, somefunc)and thendo.call(rbind, something)(though this question requires a little more).