如何用dplyr计算指定日期范围内Rates的行级累积和?
问题:计算每行指定日期区间内Rates列的累积和
需要计算数据框中每行从DATE到DATE_following日期范围内Rates列的求和结果,若区间内存在超出现有数据的日期则返回NA。示例数据及期望输出如下:
示例数据代码
library(tidyverse) library(bizdays) library(lubridate) set.seed(1) dat <- seq.Date(from = as.Date(as.Date("2023-04-06")- days(10)), to = as.Date(as.Date("2023-04-06")), by = "day") %>% data.frame(DATE = .) %>% mutate(Rates = sample(seq(from=1,to=10,by=1), size = length(DATE),replace=TRUE), DATE_following = modified.following(DATE %m+% days(3)))
运行后的数据:
DATE Rates DATE_following 1 2023-03-27 9 2023-03-30 2 2023-03-28 4 2023-03-31 3 2023-03-29 7 2023-04-01 4 2023-03-30 1 2023-04-02 5 2023-03-31 2 2023-04-03 6 2023-04-01 7 2023-04-04 7 2023-04-02 2 2023-04-05 8 2023-04-03 3 2023-04-06 9 2023-04-04 1 2023-04-07 10 2023-04-05 5 2023-04-08 11 2023-04-06 5 2023-04-09
期望输出
DATE Rates DATE_following Results 1 2023-03-27 9 2023-03-30 21 2 2023-03-28 4 2023-03-31 14 3 2023-03-29 7 2023-04-01 17 4 2023-03-30 1 2023-04-02 12 5 2023-03-31 2 2023-04-03 14 6 2023-04-01 7 2023-04-04 13 7 2023-04-02 2 2023-04-05 11 8 2023-04-03 3 2023-04-06 14 9 2023-04-04 1 2023-04-07 NA 10 2023-04-05 5 2023-04-08 NA 11 2023-04-06 5 2023-04-09 NA
询问是否可以用dplyr的rowwise()、cumsum()等函数实现,以及如何在函数中定义日期范围条件。
解决方案
可以用dplyr的rowwise()结合条件筛选实现,也可以用更高效的非rowwise方法(适合大数据量),以下两种方法都能满足需求:
方法一:使用rowwise()逐行计算
这种方法逻辑直观,适合小数据量:
dat_result <- dat %>% rowwise() %>% mutate( # 提取当前行日期区间内的所有Rates值 filtered_rates = list(dat$Rates[dat$DATE >= DATE & dat$DATE <= DATE_following]), # 检查区间内的日期是否全部存在于数据中 has_all_dates = all(seq.Date(DATE, DATE_following, by = "day") %in% dat$DATE), # 满足条件则求和,否则返回NA Results = if(has_all_dates) sum(filtered_rates) else NA ) %>% ungroup() %>% select(-filtered_rates, -has_all_dates)
代码说明:
rowwise():将数据框转为逐行处理模式,确保每行独立计算。list(...):用列表保存筛选出的Rates值,避免因行内元素数量不同导致的报错。has_all_dates:验证日期区间内的每一天都存在于原始数据的DATE列,保证数据完整性。- 最后取消分组并清理临时计算列,得到目标结果。
方法二:非rowwise的高效方法(适合大数据)
如果数据量较大,rowwise()效率较低,可以用map2()结合向量操作:
dat_result <- dat %>% mutate( Results = map2_dbl(DATE, DATE_following, ~{ date_range <- seq.Date(.x, .y, by = "day") if(all(date_range %in% dat$DATE)) { sum(dat$Rates[dat$DATE %in% date_range]) } else { NA_real_ } }) )
代码说明:
map2_dbl():遍历每一对DATE和DATE_following,返回数值型结果。- 对每一对日期生成完整的日期序列,检查是否全部存在于数据中,存在则求和,否则返回NA。
运行上述任意一种方法,都能得到你期望的输出结果。
内容的提问来源于stack exchange,提问作者mathstruggler
相关产品推荐
相关产品推荐

