使用RANGE而不是PHYSICAL分区的快速R滑动窗口功能

时间:2017-04-17 01:18:51

标签: c++ r

我正在尝试解决一个问题:在不规则的时间序列数据集上运行统计(计数;求和;平均值),其中每行的窗口大小在给定的日期范围内(最好是在分组列上) 。 我发现ORACLE SQL通过以下方式支持:

 COUNT(*) OVER (
    ORDER BY payment_date 
    RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND CURRENT ROW
  )

在R中,我构建了一些函数,这些函数使用列表来收集每行的值向量,但这很昂贵且速度很慢。我找到的最好的解决方案是用户:mgahan是他的包裹boRingTrees: R: fast sliding window with given coordinates

library("devtools")
install_github("boRingTrees","mgahan")
library("boRingTrees")

set.seed(1)
Trans_Dates <- as.Date(c(31,33,65,96,150,187,210,212,240,273,293,320,
                         32,34,66,97,151,188,211,213,241,274,294,321,
                         33,35,67,98,152,189,212,214,242,275,295,322),origin="2010-01-01")
Cust_ID <- c(rep(1,12),rep(2,12),rep(3,12))
Target <- rpois(36,3)
require("data.table")
data <- data.table(Trans_Dates,Cust_ID,Target)

data[,Roll:=rollingByCalcs(data=data,bylist="Cust_ID",dates="Trans_Dates",
        target="Target",lower=0,upper=31,incbounds=T,stat=sum,na.rm=T,cores=1)]

但是,当我针对较大的数据集运行时,它的运行速度也相当慢。

我尝试了什么:

  • 使用循环中的列表返回窗口分区,但这非常慢。
  • 导入封装的用户函数,例如boRingTrees 问题很好 - 但也很慢。

我学到了什么:

  • R通过动物园和rollapply在物理分区(向上一行,分组为天/周等)方面提供了很好的支持,但对Ranged分区的支持有限(从时间戳开始的这段小时内的所有行)。 / LI>

我认为我需要:

我得出的结论是,我需要一个C函数来更快地在一系列日期中运行滑动窗口。我已经开始在R中使用C ++了,这两个Rcpp的努力接近(技术上)我认为我需要的东西:

R: Rolling window function with adjustable window and step-size for irregularly spaced observations

R: fast sliding window with given coordinates

我希望这个摘要对于试图解决类似问题的人来说是有用的整理信息(我发现难以搜索这个主题 - 稀疏信息和描述类似事物的方式非常不同)。希望有人可以帮助我构建一个更快的C ++解决方案,我可以在R(内联或.cpp)中运行。这是一个示例数据集(再次,由mgahan提供):

Trans_Dates <- as.Date(c(31,33,65,96,150,187,210,212,240,273,293,320,
                         32,34,66,97,151,188,211,213,241,274,294,321,
                         33,35,67,98,152,189,212,214,242,275,295,322),origin="2010-01-01")
Cust_ID <- c(rep(1,12),rep(2,12),rep(3,12))
Val <- rpois(36,3)
require("data.table")
data <- data.table(Trans_Dates,Cust_ID,Val)

e.g:

data[,RowRollCount31:=rollingByCalcs(data=data,bylist="Cust_ID",dates="Trans_Dates",  target="Val",lower=0,upper=31,incbounds=T,stat=length,na.rm=T)]

理想情况下,解决方案会使用&#39; interval&#39;在Oracle示例中的选项(即每行中的&#39;&amp;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39;&#39; /&#39; by_list&#39;和&#39; stat&#39; mgahan聪明地照顾的选项。

进一步阅读/对问题的一个很好的解释:

https://blog.jooq.org/2016/10/31/a-little-known-sql-feature-use-logical-windowing-to-aggregate-sliding-ranges/

非常感谢提前!

0 个答案:

没有答案