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