【问题标题】:Cumulative sum (or running-window sum) and carry-forward values in a window based on a condition in R基于 R 中的条件的窗口中的累积和(或运行窗口总和)和结转值
【发布时间】:2018-02-15 03:21:31
【问题描述】:

我的问题受到Cumulative sum in a window (or running window sum) based on a condition in R 的启发。

我想计算运行窗口总和,就像上面的帖子一样,有点扭曲。即使没有满足过滤条件的行,我也想将累积总和的值“结转”到“k”年。换句话说,我们需要向原始数据集添加行。

这个问题很有挑战性,因为我仍然不习惯在 data.table 中使用 apply 函数。

这是我的输入数据:

DFI <- structure(list(Year = c(2011, 2013, 2014, 2010, 2012, 2015), 
    Customer = c(13575, 13575, 13575, 13575, 13576, 13576), Product = c("R", 
    "R", "R", "W", "S", "R"), Rev = c(4, 1, 2, 1, 2, 2)), .Names = c("Year", 
"Customer", "Product", "Rev"), row.names = c(NA, -6L), class = "data.frame")

这是我的预期输出:

DFO <- structure(list(Year = c(2011, 2012, 2013, 2014, 2015, 2010, 2011, 
2015, 2012, 2013), Customer = c(13575, 13575, 13575, 13575, 13575, 
13575, 13575, 13576, 13576, 13576), Product = c("R", "R", "R", 
"R", "R", "W", "W", "R", "S", "S"), Rev = c(4, 0, 1, 2, 0, 1, 
0, 2, 2, 0), CumRev = c(4, 4, 1, 3, 2, 1, 1, 2, 2, 2)), .Names = c("Year", 
"Customer", "Product", "Rev", "CumRev"), class = "data.frame", row.names = c(NA, 
-10L))

关于我如何手动生成DFO的一些评论:

a) 窗口中的年数 = 2 即k=2

b) 虽然Year = 2012Customer = 13575Product = R 的条目在DFI(输入数据)中不存在,但添加它是因为来自Year = 2011 的累积总和将结转1更多年(即k-1 = 2-1 = 1)。因此,对于这一行,Rev = 0CumRev = 4

c) The entry for Year = 2015Customer = 13575Product = R 已添加,因为表中至少存在一个 Year = 2015 条目。换言之,Year 的范围要添加(或结转)取决于两件事:1)输入表中Year 的范围 2)运行窗口的长度。

现在,我确实在发布之前尝试自己解决了这个问题。我花了将近 36 个小时,我能够解决这个问题。但是,问题在于expand.grid. 在实际数据中,我的内存不足。因此,我想知道是否有更好的方法(计算成本更低且内存效率更高)来解决这个问题。

这是我的代码:

Year<-unique(DFI$Year)
  Customer<-unique(DFI$Customer)
  Product<-unique(DFI$Product)
  DFO1<-expand.grid(Year = Year,Customer = Customer,Product = Product) #generate all combinations
  DFO1<-data.table::as.data.table(DFO1)

  #Do join between DFO and DFI to add Rev
  DFO1<-DFI[DFO1,on=c("Product","Customer","Year")]

   k<-2 #Number of years  = 2
   DFO1<-DFO1[order(Customer,Product,Year)]
   DFO1[is.na(Rev)]$Rev<-0

   DFO1<-DFO1[, CumRev := sapply(Year, function(year) sum(Rev[between(Year, year-k+1, year)])), by = .(Customer, Product)][order(Customer,Product,Year)]
   DFO1<-DFO1[CumRev!=0] #Remove zero rows

   DFO<-data.table::as.data.table(DFO)
   DFO<-DFO[order(Customer,Product,Year)]
   compare(DFO1,DFO) #TRUE

作为一个刚刚开始学习在data.table 中应用apply() 的人,这对我来说很难。我很感激任何优化这个的想法。我愿意从这个过程中学习。感谢您抽出宝贵时间以及对我的任何帮助。

【问题讨论】:

  • DFO中的完整组合不存在吗?
  • @akrun - 是的。我删除了它们(使用DFO1&lt;-DFO1[CumRev!=0]),因为我们只需要结转k-1 年的累积总和。
  • 为什么没有 Year=2016, Customer=13576, Product=R 的条目?
  • @Chinsoon:感谢您的提问。有两个标准可以确定将添加哪些行max(year)k-1。请参见上面的 c) 点。如果我们有任何一个条目,例如,2016 年的任何其他客户,我们将需要它。因为year = 2016 没有条目,所以我们通过了。简单来说就是current year = 2015

标签: r dplyr data.table


【解决方案1】:

内联解释。使用@G.Grothendieck 的 Sum 函数,以及他从 Cumulative sum in a window (or running window sum) based on a condition in R 应用的 zoo::rollapplyr

k <- 2
Sum <- function(x) {
    x <- matrix(x,, 2)
    FY <- x[, 1]
    Rev <- x[, 2]
    ok <- FY >= tail(FY, 1) - k + 1
    sum(Rev[ok])
}    


setDT(DFI)
#This is prob the only difference from your solution
#create a combination of year to year + k for each Customer and product.
#Then subset to remove future years
combis <- unique(rbindlist(lapply(seq_len(k), 
    function(n) unique(DFI[, .(Year=Year+n-1, Customer, Product)]))))[
        Year <= DFI[,max(Year)]]

#lookup revenue
out <- DFI[combis, on=.(Year, Customer, Product)][,
    Rev := ifelse(is.na(Rev), 0, Rev)]

#order before summing
setorder(out, Customer,Product,Year)
out[,CumRev := zoo::rollapplyr(.SD, k, Sum, by.column = FALSE, partial = TRUE),
    by = c("Customer", "Product"), .SDcols = c("Year", "Rev")][]

【讨论】:

  • 感谢您的帮助。你能解释一下unique(DFI[, .(Year=Year+n-1, Customer, Product)]))))吗?
  • 它只需要您的产品和客户数据集并添加几年。例如,如果您的窗口为 2,其中包含客户 A、产品 P 和 Y 年,它会将客户 A、产品 P 和 Y+1 年添加到您想要的最终 Universe
猜你喜欢
  • 2020-11-17
  • 2021-04-05
  • 2012-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多