У меня есть набор данных, индексированный двумя переменными идентификатора (одна вложена в другую) и датой, и я хочу рассчитать скользящую статистику по этим данным.
Мой реальный набор данных велик (~ 200 миллионов строк), и мне понравилось увеличение скорости с помощью data.table для других задач ... но я не могу найти способ оптимального использования data.table (т.е. использовать двоичный поиск и избегать векторное сканирование) в этой задаче.
Образец данных:
set.seed(3)
dt1 <-
data.table(id1=c(rep("a",124),rep("b",124)),
id2=c(rep("x",62),rep("y",62)),
date=seq(as.Date("2012-05-01"),as.Date("2012-07-01"),"days"),
var1=rpois(124,14),
var2=rpois(124,3))
setkey(dt1,id1,id2,date)
# create uneven time spacing
dt1 <- dt1[-c(5,10,36,46,58)]
Моя конечная цель - рассчитать "скользящую статистику" для каждого дня в пределах id1 / id2, а именно:
сумма (переменная2) / сумма (переменная1)
включая все другие строки с той же комбинацией id1 / id2 и за 30 дней до этой строки.
Я не уверен, что это хороший первый шаг, но для ясности вот код для получения желаемого результата для всех идентификаторов на Date = 2012-06-12:
dt1[date < as.Date("2012-06-12") & date > as.Date("2012-06-12")-31,
list("newstat"=sum(var1)/sum(var2),
"date"=as.Date("2012-06-12")),by=list(id1,id2)]
id1 id2 newstat date
1: a x 3.925 2012-06-12
2: a y 4.396 2012-06-12
3: b x 3.925 2012-06-12
4: b y 4.396 2012-06-12
Я подумал о том, чтобы попытаться выполнить декартово само соединение на id1 и id2, а затем уменьшить полученную таблицу data.table до соответствующего диапазона дат (я не знаю, как это сделать за один шаг). Это дает мне желаемый результат, однако я не уверен, как это сделать, не используя логическое подмножество в качестве аргумента для i на этапе сокращения, который является неприемлемо медленным. Я думаю, что в этот момент я не могу использовать ключи таблицы data.table, но не знаю, как это решить ...
Пример:
dt1[setkey(dt1[,list(id1,id2,"date_grp"=date)],id1,id2),
list(date_grp,date,var1,var2)][
# Here comes slow subset
date<date_grp & date > date_grp-30,
list("newstat"=sum(var1)/sum(var2)),
by=list(id1,id2,date_grp)]
Результат:
id1 id2 date_grp newstat
1: a x 2012-05-02 0.4286
2: a x 2012-05-03 0.4000
3: a x 2012-05-04 0.2857
4: a x 2012-05-06 0.2903
5: a x 2012-05-07 0.3056
---
235: b y 2012-06-27 0.2469
236: b y 2012-06-28 0.2354
237: b y 2012-06-29 0.2323
238: b y 2012-06-30 0.2426
239: b y 2012-07-01 0.2304