如何在R语言中按Herd分组合并日期相近的观测记录并统计检测次数
解决方案:按群分组并将2个月内的检测归为同一批次
你遇到的问题核心是按群(Herd)划分时间窗口,把2个月内的所有检测记录标记为同一批次,而不是按单个日期排序。原来的dense_rank(date)会把每个不同日期都算作新批次,这不符合需求。下面是两种可靠的实现方法,都基于tidyverse工具链:
方法1:基于相邻日期间隔的动态分组(更灵活)
这种方法会自动判断当前检测日期和上一个检测日期的间隔,如果超过2个月就标记为新批次,适合检测周期不严格对齐日历的场景:
library(tidyverse) library(lubridate) # 加载你的数据 df <- data.frame( animal = c("Animal1", "Animal2", "Animal3", "Animal4", "Animal5", "Animal6", "Animal1", "Animal2", "Animal3", "Animal4", "Animal5", "Animal6", "Animal7", "Animal8", "Animal9", "Animal10", "Animal11", "Animal12", "Animal7", "Animal8", "Animal9", "Animal10", "Animal11", "Animal12"), herd = c("Herd1","Herd1","Herd1", "Herd1","Herd1","Herd1", "Herd1","Herd1","Herd1", "Herd1","Herd1","Herd1","Herd2","Herd2", "Herd2","Herd2","Herd2","Herd2", "Herd2","Herd2", "Herd2","Herd2","Herd2","Herd2"), date = c("2017-01-01", "2017-01-01", "2017-01-17","2017-02-04", "2017-02-04", "2017-02-05", "2017-06-01" , "2017-06-03", "2017-07-01", "2017-06-21", "2017-06-01", "2017-06-15", "2017-02-01", "2017-02-01", "2017-02-15", "2017-02-21", "2017-03-05", "2017-03-01", "2017-07-01", "2017-07-01", "2017-07-15", "2017-07-21", "2017-08-05", "2017-08-01") ) # 处理流程 df_with_testing <- df %>% # 第一步:把字符型日期转换为Date类型,方便计算 mutate(date = ymd(date)) %>% # 按群分组 group_by(herd) %>% # 按日期排序,确保时间顺序正确 arrange(date) %>% # 标记是否为新的检测批次:第一行默认是新批次,后续如果和上一个日期差超过2个月则标记为新批次 mutate(is_new_test = case_when( row_number() == 1 ~ TRUE, date > lag(date) + months(2) ~ TRUE, TRUE ~ FALSE )) %>% # 通过累加标记值,生成检测批次号 mutate(testing = cumsum(is_new_test)) %>% # 恢复原数据的行顺序(因为之前按日期排序了) mutate(row_id = row_number()) %>% ungroup() %>% arrange(row_id) %>% # 移除临时辅助列 select(-row_id, -is_new_test) # 查看结果 print(df_with_testing)
方法2:基于日历2月窗口的固定分组(适合严格对齐周期的场景)
如果你的检测周期严格按日历每2个月为一个窗口(比如1-2月、3-4月、5-6月等),可以直接用floor_date把日期映射到窗口起始日,再用dense_rank生成批次号:
df_with_testing <- df %>% mutate(date = ymd(date)) %>% group_by(herd) %>% # 把日期向下取整到2个月窗口的起始日(比如1月、3月、5月...) mutate(window_start = floor_date(date, "2 months")) %>% # 对窗口起始日排序生成批次号 mutate(testing = dense_rank(window_start)) %>% ungroup() %>% select(-window_start) print(df_with_testing)
验证结果
两种方法都会生成你期望的testing列:
- Herd1的1-2月检测统一标记为
1,6-7月检测标记为2 - Herd2的2-3月检测统一标记为
1,7-8月检测标记为2
你可以根据实际检测周期的灵活性选择合适的方法,如果检测窗口可能跨日历月(比如1月中旬到3月中旬),方法1会更准确。
内容的提问来源于stack exchange,提问作者Gómez-Buendía A.
相关产品推荐
相关产品推荐

