我正在努力有效地在两个数据框之间执行“关闭”日期匹配。这个问题探索了使用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

10-07 19:57
查看更多