Я изо всех сил пытаюсь эффективно выполнить «близкое» совпадение даты между двумя фреймами данных.В этом вопросе рассматривается решение с использованием 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
, которое происходит ПОСЛЕ даты в sampleticker
.В прошлом я решал подобные проблемы, выполняя простое слияние в поле тикера, сортируя по возрастанию, а затем выбирая уникальные комбинации тикера и даты.Однако из-за размера этого набора данных слияние происходит очень быстро.
Насколько я могу судить, merge
не допускает такого рода приблизительного сопоставления.Я видел некоторые решения, в которых используется 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
является экспериментальным, поэтому я не обязательно ожидал, что он будет работать должным образом.Однако, если у кого-то есть идея, как это исправить, я был бы признателен.С другой стороны, если бы кто-то мог предложить совершенно другой подход, который работает более эффективно, это было бы фантастически.
Matt
UPDATE Data.table - правильный путьэтот.Смотри ниже.