Операции условного столбца строки в data.table

У меня есть большая data.table, где я для каждой строки нужно делать вычисления на основе части полной таблицы данных. В качестве примера рассмотрим следующую таблицу данных и предположим, что для каждой строки я хочу вычислить сумму переменной num для всех строк, где id2 соответствует id1 для текущей строки, а также временная переменная находится на расстоянии 1 от времени текущей строки.

set.seed(123)

dat <- data.table(cbind(id1=sample(1:5,10,replace=T),
                        id2=sample(1:5,10,replace=T),
                        num=sample(1:10,10,replace=T),
                        time=sample(1:10,10,replace=T)))

Это можно легко сделать, перейдя по каждой строке, подобной этой

dat[,val:= 0]
for (i in 1:nrow(dat)){
  this.val <- dat[ (id2==id1[i]) & (time>=time[i]-2) & (time<=time[i]+2),sum(num)]
  dat[i,val:=this.val]
}

dat

Полученная таблица данных выглядит следующим образом:

   > dat
        id1 id2 num time val
     1:   2   5   9   10   6
     2:   4   3   7   10   0
     3:   3   4   7    7  10
     4:   5   3  10    8   9
     5:   5   1   7    1   2
     6:   1   5   8    5   6
     7:   3   2   6    8  17
     8:   5   1   6    3  10
     9:   3   2   3    4   0
    10:   3   5   2    3   0

Каков правильный/быстрый способ делать такие вещи, используя data.table?

Ответ 1

Мы можем использовать самосоединение здесь, создав столбец "timeminus2" и "timeplus2", присоедините on к "id2" с "id1" и неравновесное условие, чтобы получить sum of ' num 'и присвойте (:=) столбец "val" исходному набору данных

tmp <- dat[.(id1 = id1, timeminus2 = time - 2, timeplus2 = time + 2), 
             .(val = sum(num)),
             on = .(id2 = id1, time >= timeminus2, time <= timeplus2),
             by = .EACHI
         ][is.na(val), val := 0][]
dat[, val := tmp$val][]
#     id1 id2 num time val
# 1:   2   5   9   10   6
# 2:   4   3   7   10   0
# 3:   3   4   7    7  10
# 4:   5   3  10    8   9
# 5:   5   1   7    1   2
# 6:   1   5   8    5   6
# 7:   3   2   6    8  17
# 8:   5   1   6    3  10
# 9:   3   2   3    4   0
#10:   3   5   2    3   0