我正在努力有效地在两个数据框之间执行“关闭”日期匹配。这个问题探索了使用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
的解决方案,但是由于日期之间的距离会有所不同,因此我不确定是否可以指定一个适用于所有行的间隔。在另一篇here之后,我编写了以下代码,以在每一行上使用
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多个子集操作,因此它非常慢:我将上述查询运行了一天以上,最后才将其杀死。
我看到here表示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
是实验性的,因此我不一定希望它能正常工作。但是,如果有人对如何解决此问题有想法,我将不胜感激。或者,如果有人可以提出一种完全不同的方法来更有效地运行,那就太好了。马特
UPDATE Data.table是解决此问题的正确方法。见下文。
最佳答案
感谢Matthew Dowle及其在data.table中向前和向后滚动的功能的添加,现在可以更轻松地执行此合并。
ST <- data.table(sampleticker)
SR <- data.table(samplereport)
setkey(ST,ticker,date)
SR[,mergerdate:=rdate]
setkey(SR,ticker,mergerdate)
merge<-SR[ST,roll=-Inf]
setnames(merge,"mergerdate","date")
# ticker date rdate
# 1: A 2005-01-25 2005-02-15
# 2: A 2005-03-30 2005-04-15
# 3: AA 2005-02-15 2005-03-01
# 4: AA 2005-04-21 2005-05-01