【问题标题】:Moving sum over date range在日期范围内移动总和
【发布时间】:2014-07-27 01:25:18
【问题描述】:

我有这张表,其中包含广泛的日期和每个日期的对应值,示例如下所示。

Date        Value   
6/01/2013   8   
6/02/2013   4   
6/03/2013   1   
6/04/2013   7   
6/05/2013   1   
6/06/2013   1   
6/07/2013   3   
6/08/2013   8   
6/09/2013   4   
6/10/2013   2   
6/11/2013   10  
6/12/2013   4   
6/13/2013   7   
6/14/2013   3   
6/15/2013   2   
6/16/2013   1   
6/17/2013   7   
6/18/2013   5   
6/19/2013   1   
6/20/2013   4   

我要做的是创建一个查询,该查询将创建一个新列,该列将显示指定日期范围内值列的总和。例如在下面,总和列包含其对应日期的总和,该日期可追溯到一整周。因此,日期 6/9/2013 的总和将是从 6/03/2013 到 6/09/2013 的值的总和。

Date        Sum
6/01/2013   8
6/02/2013   12
6/03/2013   13
6/04/2013   20
6/05/2013   21
6/06/2013   22
6/07/2013   25
6/08/2013   25
6/09/2013   25
6/10/2013   26
6/11/2013   29
6/12/2013   32
6/13/2013   38
6/14/2013   38
6/15/2013   32
6/16/2013   29
6/17/2013   34
6/18/2013   29 
6/19/2013   26
6/20/2013   23

我尝试使用 LIMIT 子句,但我无法让它工作,任何帮助将不胜感激。

【问题讨论】:

  • 我正在尝试对 data.table 做同样的事情。我可以“思考”它,但我做不到。每个运行周都需要一个 .SD 来分块,但 i 参数需要为每一行更改。让我看看能不能把data.table带进去?
  • 这是一个data.table 解决方案stackoverflow.com/questions/24397299/…

标签: sql r count sum data.table


【解决方案1】:

zoo 有一个函数 rollapply 可以做你需要的:

z <- zoo(x$Value, order.by=x$Date)

rollapply(z, width = 7, FUN = sum, partial = TRUE, align = "right")
## 2013-06-01                                                                   8
## 2013-06-02                                                                  12
## 2013-06-03                                                                  13
## 2013-06-04                                                                  20
## 2013-06-05                                                                  21
## 2013-06-06                                                                  22
## 2013-06-07                                                                  25
## 2013-06-08                                                                  25
## 2013-06-09                                                                  25
## 2013-06-10                                                                  26
## 2013-06-11                                                                  29
## 2013-06-12                                                                  32
## 2013-06-13                                                                  38
## 2013-06-14                                                                  38
## 2013-06-15                                                                  32
## 2013-06-16                                                                  29
## 2013-06-17                                                                  34
## 2013-06-18                                                                  29
## 2013-06-19                                                                  26
## 2013-06-20                                                                  23

【讨论】:

  • 但是如果每天都没有自己的行会怎样呢?换句话说,有些日子可能没有数据。或者如果有些日子有两行会发生什么?您的解决方案有效,因为它需要最后 7 行,但它假设这代表一个时间范围?有没有办法做到这一点,但通过计算时间范围?
【解决方案2】:

使用data.table

require(data.table)

#Build some sample data
data <- data.table(Date=1:20,Value=rpois(20,10))

#Build reference table
Ref <- data[,list(Compare_Value=list(I(Value)),Compare_Date=list(I(Date)))]

#Use lapply to get last seven days of value by id
data[,Roll.Val := lapply(Date, function(x) {
                  d <- as.numeric(Ref$Compare_Date[[1]] - x)
                  sum((d <= 0 & d >= -7)*Ref$Compare_Value[[1]])})]

head(data,10)

    Date Value Roll.Val
 1:    1    14       14
 2:    2     7       21
 3:    3     9       30
 4:    4     5       35
 5:    5    10       45
 6:    6    10       55
 7:    7    15       70
 8:    8    14       84
 9:    9     8       78
10:   10    12       83

如果有人感兴趣,这里是另一种解决方案:

library("devtools")
install_github("boRingTrees","mgahan")
require(boRingTrees)
rollingByCalcs(data,dates="Date",target="Value",stat=sum,lower=0,upper=7)

【讨论】:

  • 另一种方式,似乎要快得多,描述于stackoverflow.com/a/27983553/2490497
  • 干得好!但另一个组成部分是内存使用。不知道这些比较如何。对于大数据集,这是一个关键点。我认为这是有希望的。
【解决方案3】:

这是一种方法

> input <- read.table(text = "Date        Value   
+ 6/01/2013   8   
+ 6/02/2013   4   
+ 6/03/2013   1   
+ 6/04/2013   7   
+ 6/05/2013   1   
+ 6/06/2013   1   
+ 6/07/2013   3   
+ 6/08/2013   8   
+ 6/09/2013   4   
+ 6/10/2013   2   
+ 6/11/2013   10  
+ 6/12/2013   4   
+ 6/13/2013   7   
+ 6/14/2013   3   
+ 6/15/2013   2   
+ 6/16/2013   1   
+ 6/17/2013   7   
+ 6/18/2013   5   
+ 6/19/2013   1   
+ 6/20/2013   4   ", as.is = TRUE, header = TRUE)
> input$Date <- as.Date(input$Date, format = "%m/%d/%Y")  # convert Date
> 
> # create a sequence that goes a week back from the current data
> x <- data.frame(Date = seq(min(input$Date) - 6, max(input$Date), by = '1 day'))
> 
> # merge
> merged <- merge(input, x, all = TRUE)
> 
> # replace NAs with zero
> merged$Value[is.na(merged$Value)] <- 0L
> 
> # use 'filter' for the running sum and delete first 6
> input$Sum <- filter(merged$Value, rep(1, 7), sides = 1)[-(1:6)]
> input
         Date Value Sum
1  2013-06-01     8   8
2  2013-06-02     4  12
3  2013-06-03     1  13
4  2013-06-04     7  20
5  2013-06-05     1  21
6  2013-06-06     1  22
7  2013-06-07     3  25
8  2013-06-08     8  25
9  2013-06-09     4  25
10 2013-06-10     2  26
11 2013-06-11    10  29
12 2013-06-12     4  32
13 2013-06-13     7  38
14 2013-06-14     3  38
15 2013-06-15     2  32
16 2013-06-16     1  29
17 2013-06-17     7  34
18 2013-06-18     5  29
19 2013-06-19     1  26
20 2013-06-20     4  23
> 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-12
    • 2015-08-12
    • 2018-03-05
    • 2020-06-12
    • 2021-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多