【发布时间】:2012-03-05 08:47:01
【问题描述】:
我正在努力在两个数据框之间有效地执行“关闭”日期匹配。这个问题探讨了使用 plyr 包中的 idata.frame 的解决方案,但我也会对其他建议的解决方案感到非常满意。
这是两个数据框的一个非常简单的版本:
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.
请注意,在普通的旧 samplereport 上调用 as.data.frame 会按预期返回原始数据帧。
我知道idata.frame 是实验性的,所以我不一定期望它能够正常工作。但是,如果有人对如何解决此问题有任何想法,我将不胜感激。或者,如果有人能提出一种运行效率更高的完全不同的方法,那就太好了。
马特
更新 Data.table 是解决此问题的正确方法。见下文。
【问题讨论】:
标签: r data.table plyr subset