我正在努力高效地執行兩個數據幀之間的「關閉」日期匹配。這個問題使用plyr
軟件包中的idata.frame
來探索解決方案,但我也會對其他建議的解決方案感到非常滿意。R - 加速近似日期匹配。 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
25列近30萬行。
我想這樣做是爲了讓在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
是實驗性的,所以我不一定期望它能正常工作。但是,如果任何人有關於如何解決這個問題的想法,我將不勝感激。或者,如果任何人都可以提出更有效運行的完全不同的方法,那就太棒了。
馬特
UPDATE Data.table是去的正確方法。見下文。
而且,您還可以通過輸入負數而不是「Inf」來限制卷的數量。神奇的東西! – Matt 2013-03-06 22:29:59
非常好。感謝您發佈此信息。 – 2013-03-06 22:35:18