Мне нужно выполнить следующую рекурсивную строку за строкой, чтобы получить z
:
myfun = function (xb, a, b) {
z = NULL
for (t in 1:length(xb)) {
if (t >= 2) { a[t] = b[t-1] + xb[t] }
z[t] = rnorm(1, mean = a[t])
b[t] = a[t] + z[t]
}
return(z)
}
set.seed(1)
n_smpl = 1e6
ni = 5
id = rep(1:n_smpl, each = ni)
smpl = data.table(id)
smpl[, time := 1:.N, by = id]
a_init = 1; b_init = 1
smpl[, ':=' (a = a_init, b = b_init)]
smpl[, xb := (1:.N)*id, by = id]
smpl[, z := myfun(xb, a, b), by = id]
Я хотел бы получить такой результат:
id time a b xb z
1: 1 1 1 1 1 0.3735462
2: 1 2 1 1 2 2.7470924
3: 1 3 1 1 3 8.4941848
4: 1 4 1 1 4 20.9883695
5: 1 5 1 1 5 46.9767390
---
496: 100 1 1 1 100 0.3735462
497: 100 2 1 1 200 200.7470924
498: 100 3 1 1 300 701.4941848
499: 100 4 1 1 400 1802.9883695
500: 100 5 1 1 500 4105.9767390
Это работает, но требует времени:
system.time(smpl[, z := myfun(xb, a, b), by = id])
user system elapsed
33.646 0.994 34.473
Мне нужно сделать это быстрее, учитывая размер моих фактических данных (более 2 миллионов наблюдений). Я думаю, do.call(myfun, .SD), .SDcols = c('xb', 'a', 'b')
с by = .(id, time)
будет намного быстрее, избегая цикла for внутри myfun
. Тем не менее, я не был уверен, как я могу обновить b
и его отставание (возможно, используя shift
), когда я запускаю эту строку за строкой в data.table
. Любые предложения?