Оптимизация кода data.table для нарезки и вычислений

вот мини-пример, чтобы проиллюстрировать мою задачу. У меня есть большой набор данных, скажем, таблица данных dt, с датой столбцов, exdate (срок выполнения) и ценой X (например, цена доставки в exdate).

date          exdate       X
1999-01-01   1999-02-01   100
1999-01-01   1999-01-17    50
1999-01-01   1999-05-01    75
1999-01-02   1999-01-17    60
1999-01-02   1999-04-02    50
...            ...         ...

и так далее. Теперь я хочу выполнить определенный анализ:

  1. Для каждой даты и каждого эксдата я хочу применить функции ко всем ценам, соответствующим эксдатам больше, чем текущий эксдат. (например, проверьте, выше ли цена: sapply(dt[date==date[1] & exdate > exdate[1],X],function(x) x>dt[date==date[1] & exdate = exdate[1],X])
  2. То же, что и 1., но теперь берем те же эксдаты и ищем все товары, соответствующие ценам, превышающим текущую, и снова применяя определенные формулы.

Я пробовал эту нарезку с комбинацией метода data.table, показанного в 1, и вложенных циклов for, повторяющихся по каждому столбцу. Излишне говорить, что это занимает довольно много времени.

Следующей моей идеей было использовать многомерный массив для одновременного выполнения анализа, но я не смог заставить его работать.

Моей последней попыткой было изучение вариантов data.tables .SD и .GRP, но и этот подход не был плодотворным, хотя я думал, что просто что-то здесь упускаю и это может быть вариант.

Я довольно много читал на этом форуме о нарезке и оптимизации, но, учитывая, что формулы, которые я применяю, нетривиальны (например, можно рассмотреть среднее/сумму/среднее), я не смог применить данные решения.

Поэтому, если кто-то имел дело с такой проблемой/задачей раньше или знает об этом, я был бы очень признателен за любую помощь, которую я могу получить!

Спасибо!


person Daedalus    schedule 23.08.2017    source источник
comment
Что касается 2-го вопроса, пожалуйста, что подразумевается под продуктами? К какому столбцу в наборе выборочных данных это относится?   -  person Uwe    schedule 23.08.2017


Ответы (1)


Что касается первого вопроса, то его можно решить с помощью неэквивалентных самосоединений data.table:

library(data.table)   # CRAN version 1.10.4 used
# coerce to data.table and order data for later comparisons
setorder(setDT(DT), date, exdate, X)
# non-equi self-join
DT[DT, on = c("date", "exdate>=exdate"), 
   # aggregate
   .(min.X = min(X), min.exdate = x.exdate[which.min(X)], n.lt.1st = sum(X < first(X)),
     max.X = max(X), max.exdate = x.exdate[which.max(X)], n.gt.1st = sum(X > first(X))), 
   # for each join group
   by = .EACHI]
         date     exdate min.X min.exdate n.lt.1st max.X max.exdate n.gt.1st
1: 1999-01-01 1999-01-17    50 1999-01-17        0   100 1999-02-01        2
2: 1999-01-01 1999-02-01    75 1999-05-01        1   100 1999-02-01        0
3: 1999-01-01 1999-05-01    75 1999-05-01        0    75 1999-05-01        0
4: 1999-01-02 1999-01-17    50 1999-04-02        1    60 1999-01-17        0
5: 1999-01-02 1999-04-02    50 1999-04-02        0    50 1999-04-02        0

Агрегаты — это просто примеры, которые показывают минимальное значение, exdate минимального значения, числовые значения меньше первого значения и, соответственно, то же самое для максимального значения.

Обратите внимание, что условие exdate>=exdate, а не exdate>exdate. Это необходимо для включения эталонной строки в набор результатов для сравнения с ней, т. е. X < first(X).

Что касается второго вопроса, неясно, что означает продукт.

Данные

library(data.table)
DT <- fread(
  "date          exdate       X
1999-01-01   1999-02-01   100
1999-01-01   1999-01-17    50
1999-01-01   1999-05-01    75
1999-01-02   1999-01-17    60
1999-01-02   1999-04-02    50"
)
cols <- c("date", "exdate")
DT[, (cols) := lapply(.SD, as.IDate), .SDcols = cols]
str(DT)
Classes ‘data.table’ and 'data.frame':    5 obs. of  4 variables:
 $ date   : IDate, format: "1999-01-01" "1999-01-01" "1999-01-01" "1999-01-02" ...
 $ exdate : IDate, format: "1999-01-17" "1999-02-01" "1999-05-01" "1999-01-17" ...
 $ X      : int  50 100 75 60 50
 $ refdate: IDate, format: "1999-01-17" "1999-02-01" "1999-05-01" "1999-01-17" ...
 - attr(*, ".internal.selfref")=<externalptr>

Обратите внимание, что используется собственный класс даты datatables IDate с целочисленным хранилищем.

person Uwe    schedule 23.08.2017
comment
Спасибо, мне нужно будет пройти через это и прочитать о неэквивалентных самостоятельных соединениях, но это может решить эту проблему. Каждая строка представляет один продукт, поэтому вторая часть должна быть аналогична первой с использованием вашего метода. - person Daedalus; 23.08.2017
comment
Могу ли я порекомендовать @Frank Краткое руководство по R, раздел 3.5? - person Uwe; 23.08.2017