我正试图创建一个函数,将最接近给定日期的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
,这是错误的,原因有很多:
- 我的
if
语句只在第一周出现,所以滞后总是NA,领先总是非NA - 我需要有一种方法,看看它第一次是否使用滞后/领先。第一个值是
6
而不是8
,因为第一个for循环将其发送到lead(_,1),但第二个for循环也会这样做。我想不出如何让我的第二个for循环识别出这一点
是否有函数或库(Zoo
?)可以简化此任务?为了练习/理解,我想让自己的功能发挥作用,但在这一点上,我宁愿完成它。
谢谢!
为了详细说明我的评论,lead
和lag
是要在矢量化函数(如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