Как рассчитать скользящую статистику в R с использованием таблицы data.table для данных с неравномерным интервалом

У меня есть набор данных, индексированный двумя переменными идентификатора (одна вложена в другую) и датой, и я хочу рассчитать скользящую статистику по этим данным.

Мой реальный набор данных велик (~ 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

person co_biostat    schedule 26.03.2014    source источник


Ответы (1)


Я уверен, что есть лучший способ сделать это, но вы можете избежать полного декартова соединения, которое убивает вас, создав промежуточную таблицу с ключами соединения:

dt.dates <- dt1[, list(date.join=seq(as.Date(date - 1, origin="1970-01-01"), by="-1 day", len=30)), by=list(date, id1, id2)]

Для каждой группы идентификаторов даты мы сгенерировали список допустимых дат присоединения. Теперь мы снова присоединяемся к данным и вычисляем нашу метрику.

setkey(dt.dates, date.join, id1, id2)
setkey(dt1,date,id1,id2)
dt.dates[dt1][ , sum(var1)/sum(var2), by=list(id1, id2, date)]

Я не смог воспроизвести ваш результат за 6/12, но я думаю, что у нас проблема с посевом. Сравнивать:

> dt.date.join[dt1][ , sum(var1)/sum(var2), by=list(id1, id2, date)][date=="2012-06-12"]
   id1 id2       date       V1
1:   a   x 2012-06-12 3.630631
2:   a   y 2012-06-12 4.434783
3:   b   x 2012-06-12 3.634783
4:   b   y 2012-06-12 4.434783
> 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.630631 2012-06-12
2:   a   y 4.434783 2012-06-12
3:   b   x 3.634783 2012-06-12
4:   b   y 4.434783 2012-06-12

Практически тот же результат.

person BrodieG    schedule 26.03.2014
comment
Отличная мысль, предварительный расчет возможных объединений исключает последующее медленное подмножество. В ответ на ваш комментарий о том, что декартово соединение - это то, что меня убивает, декартово соединение и последующий объем памяти являются быстрыми / приемлемыми (data.table действительно быстр!). Однако последующее подмножество, основанное на диапазонах дат, - это то, что длится вечно. Ваш ответ избегает этого подмножества, поэтому большое вам спасибо! - person co_biostat; 26.03.2014