r-(dplyr)某个日期最近的N个值的总和

  • 本文关键字:最近 日期 dplyr r dplyr
  • 更新时间 :
  • 英文 :


我正试图创建一个函数,将最接近给定日期的n个值求和。因此,如果我有5周的数据,n=2,第1周的值将是第2周的总和;第2周的值将是第1&3等示例:

library(dplyr)
library(data.table)
Week <- 1:5
Sales <- c(1, 3, 5, 7, 9)
frame <- data.table(Week, Sales)
frame
Week Sales  Recent
1:    1     1    8
2:    2     3    6
3:    3     5    10
4:    4     7    14
5:    5     9    12

我想做一个函数来为我做这件事,输入最近的n(不仅仅是2),但现在我想得到2。这是我使用滞后/超前的函数:

RecentSum = function(Variable, Lags){
Sum = 0
for(i in 1:(Lags/2)){ #Lags/2 because I want half values before and half after
#Check to see if you can go backwards. If not, go foward (i.e. use lead).
if(is.na(lag(Variable, i))){
LoopSum = lead(Variable, i)
}
else{
LoopSum = lag(Variable, i)
}
Sum = Sum + LoopSum
}
for(i in 1:(Lags/2)){
if(is.na(lead(Variable, i))){ #Check to see if you can go forward. If not, go backwards (i.e. use lag).
LoopSum = lag(Variable, i)
}
else{
LoopSum = lead(Variable, i)
}
Sum = Sum + LoopSum
}
Sum
}

当我做RecentSum(frame$Sale,2)时,我得到了[1] 6 10 14 18 NA,这是错误的,原因有很多:

  1. 我的if语句只在第一周出现,所以滞后总是NA,领先总是非NA
  2. 我需要有一种方法,看看它第一次是否使用滞后/领先。第一个值是6而不是8,因为第一个for循环将其发送到lead(_,1),但第二个for循环也会这样做。我想不出如何让我的第二个for循环识别出这一点

是否有函数或库(Zoo?)可以简化此任务?为了练习/理解,我想让自己的功能发挥作用,但在这一点上,我宁愿完成它。

谢谢!

为了详细说明我的评论,leadlag是要在矢量化函数(如dplyr)中使用的函数。以下是一种在dplyr中执行此操作而不使用函数的方法:

df <- tibble(week = Week, sales = Sales)
df %>%
mutate(recent = case_when(is.na(lag(sales)) ~ lead(sales, n = 1) + lead(sales, n = 2),
is.na(lead(sales)) ~ lag(sales, n = 1) + lag(sales, n = 2),
TRUE ~ lag(sales) + lead(sales)))

这给了你这个:

# A tibble: 5 x 3
week sales recent
<int> <dbl>  <dbl>
1     1     1      8
2     2     3      6
3     3     5     10
4     4     7     14
5     5     9     12

1)假设k甚至将to定义为索引的向量,使得对于to的每个元素,我们对Sales的以该索引结束的k+1个元素求和,并从中减去Sales:

k <- 2  # number of elements to sum
n <- nrow(frame)
to <- pmax(k+1, pmin(1:n + k/2, n))
Sum <- function(to, Sales) sum(Sales[seq(to = to, length = k+1)])
frame %>% mutate(recent = sapply(to, Sum, Sales) - Sales)

给予:

Week Sales recent
1    1     1      8
2    2     3      6
3    3     5     10
4    4     7     14
5    5     9     12    

请注意,通过用以下行替换上面的最后一行代码,可以完全在基本R中完成解决方案:

transform(frame, recent = sapply(to, Sum, Sales) - Sales)

2)这将Sales系列前后的适当元素连接在一起,以便使用普通的滚动和得出结果。

library(zoo)
ix <- c(seq(to = k+1, length = k/2), 1:n, seq(to = n-k, length = k/2))
frame %>% mutate(recent = rollsum(Sales[ix], k+1) - Sales)

注意,如果k=2,那么它将其减少为一个线性:

frame %>% mutate(recent = rollsum(Sales[c(3, 1:n(), n()-2)], 3) - Sales)

给予:

Week Sales recent
1    1     1      8
2    2     3      6
3    3     5     10
4    4     7     14
5    5     9     12

更新:已修复k>2

最新更新