dplyr分组外特征汇总问题:按ids和date分组后基于全局特征统计事件数
解决按ID和日期分组,统计前后30天事件总数的问题
你的核心需求是:对每个ids和date的组合,统计该ids在当前date前后30天内的所有事件总数,但当前代码没有实现这个逻辑,问题出在分组后的条件判断上。
原代码的问题分析
当你用group_by(ids, date)分组后,每个分组里的date是单一固定值,所以date >= date - 30 & date <= date这个条件永远为TRUE,最终events统计的只是每个(ids, date)分组内的记录数,而不是跨日期窗口的总事件数。
解决方案
下面提供几种可靠的实现方式,你可以根据数据量选择:
方法1:自连接(逻辑清晰,易理解)
通过自连接匹配同一ID下的所有日期记录,再筛选出目标日期的30天窗口范围,最后统计数量:
library(dplyr) library(lubridate) set.seed(100) df <- data.frame( ids = sample(c('436247', '2465347', '346654645'), 10000, replace=TRUE), date = sample(seq.Date(ymd('2018-03-01'), ymd('2018-05-01'), by=1), 10000, replace=TRUE) ) new_df <- df %>% # 重命名原始日期为target_date,避免连接后混淆 rename(target_date = date) %>% # 按ID连接到原始数据集,获取该ID的所有日期记录 inner_join(df, by = "ids") %>% # 筛选出在target_date前后30天内的记录 filter(date >= target_date - days(30), date <= target_date + days(30)) %>% # 按ID和目标日期分组,统计事件数 group_by(ids, target_date) %>% summarise(events = n(), .groups = "drop") %>% # 把target_date改回原命名date rename(date = target_date)
方法2:逐行窗口统计(中等数据量适用)
利用rowwise()逐行计算每个日期对应的30天窗口内的事件数:
new_df <- df %>% group_by(ids) %>% rowwise() %>% # 对当前行的date,统计同一ID下所有在[date-30, date+30]的记录数 mutate(events = sum(between(date, !!cur_data()$date - days(30), !!cur_data()$date + days(30)))) %>% ungroup() %>% # 去重,保留每个(ids, date)的唯一统计结果 distinct(ids, date, .keep_all = TRUE)
方法3:data.table非等值连接(大数据量高效处理)
如果你的数据集非常大(百万级以上),推荐用data.table的非等值连接,速度远快于dplyr:
library(data.table) library(lubridate) setDT(df) new_df <- df[df, on = .(ids, date >= date - days(30), date <= date + days(30)), .(events = .N), by = .EACHI] %>% # 调整列名,还原原始date字段 setnames(c("date", "date.1"), c("window_start", "window_end")) %>% mutate(date = window_end) %>% select(ids, date, events)
验证结果
你可以随机抽取几个(ids, date)组合,手动核对事件数是否符合预期,比如:
# 查看某个ID在特定日期的事件数 filter(new_df, ids == '436247', date == ymd('2018-04-01'))
内容的提问来源于stack exchange,提问作者Matt W.
相关产品推荐
相关产品推荐

