我正在努力有效地在两个数据框之间执行“关闭”日期匹配。这个问题探讨了使用包中的解决方案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
普通的 oldsamplereport
会按预期返回原始数据帧。
我知道这idata.frame
是实验性的,所以我不一定期望它能够正常工作。但是,如果有人对如何解决此问题有任何想法,我将不胜感激。或者,如果有人能提出一种运行效率更高的完全不同的方法,那就太好了。
马特
UPDATE Data.table 是解决此问题的正确方法。见下文。