R - Ускорение приблизительного совпадения даты. idata.frame?

Я изо всех сил пытаюсь эффективно выполнить сопоставление даты «закрытия» между двумя фреймами данных. В этом вопросе исследуется решение с использованием idata.frame из пакета plyr , но я был бы очень рад и другим предлагаемым решениям.

Вот очень упрощенная версия двух фреймов данных:

sampleticker<-data.frame(cbind(ticker=c("A","A","AA","AA"),
  date=c("2005-1-25","2005-03-30","2005-02-15","2005-04-21")))
sampleticker$date<-as.Date(sampleticker$date,format="%Y-%m-%d")

samplereport<-data.frame(cbind(ticker=c("A","A","A","AA","AA","AA"),
  rdate=c("2005-2-15","2005-03-15","2005-04-15",
  "2005-03-01","2005-04-20","2005-05-01")))
samplereport$rdate<-as.Date(samplereport$rdate,format="%Y-%m-%d")

В реальных данных, sampleticker составляет более 30 000 строк с 40 столбцами, а samplereport почти 300 000 строк с 25 столбцов.

Я хотел бы объединить два фрейма данных, чтобы каждая строка в sampleticker объединялась с ближайшим совпадением даты в samplereport , которое происходит ПОСЛЕ даты в сэмплер . Раньше я решал аналогичные проблемы, выполняя простое слияние в поле тикера, сортируя по возрастанию, а затем выбирая уникальные комбинации тикера и даты. Однако из-за размера этого набора данных слияние происходит очень быстро.

Насколько я могу судить, слияние не допускает такого приблизительного сопоставления. Я видел некоторые решения, в которых используется findInterval , но, поскольку расстояние между датами будет варьироваться, я не уверен, что могу указать интервал, который будет работать для всех строк.

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

library(plyr)
merge<-adply(sampleticker,1,function(x){
  y<-subset(samplereport,ticker %in% x$ticker & rdate > x$date)
  y[which.min(y$rdate),]
  }))

Это работает довольно хорошо: для образцов данных , Я получаю то, что хочу.

   date       ticker      rdate
 1 2005-01-25  A          2005-02-15
 2 2005-03-30  A          2005-04-15
 3 2005-02-15  AA         2005-03-01
 4 2005-04-21  AA         2005-05-01

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

Я вижу здесь , что plyr 1.0 имеет структуру, idata.frame , которая вызывает фрейм данных по ссылке, что значительно ускоряет операцию поднабора. Однако я не могу заставить работать следующий код:

isamplereport<-idata.frame(samplereport)
adply(sampleticker,1,function(x){
  y<-subset(isamplereport,isamplereport$ticker %in% x$ticker & 
    isamplereport$rdate > x$date)
  y[which.min(y$rdate),]
})

Я получаю сообщение об ошибке

Error in list_to_dataframe(res, attr(.data, "split_labels")) : 
Results must be all atomic, or all data frames

Это имеет смысл для меня, поскольку операция возвращает idata.frame (я полагаю). Однако изменение последней строки на:

as.data.frame(y[which.min(y$rdate),]) 

также вызывает ошибку:

Error in `[.data.frame`(x$`_data`, x$`_rows`, x$`_cols`) : 
undefined columns selected.

Обратите внимание, что вызов as.data.frame в простом старом samplereport возвращает исходный фрейм данных, как и ожидалось.

Я знаю, что idata.frame является экспериментальным, поэтому я не ожидал, что он будет работать должным образом. Однако, если у кого-то есть идея, как это исправить, я был бы признателен. С другой стороны, если бы кто-нибудь мог предложить совершенно другой подход, который работает более эффективно, это было бы фантастически.

Мэтт

ОБНОВЛЕНИЕ Data.table - правильный способ решить эту проблему. Увидеть ниже.

7
задан Community 23 May 2017 в 10:29
поделиться