如何用dplyr将事件起止日期扩展为非平衡月度面板?
用dplyr实现非平衡月度面板的解决方案
哈哈,这个问题我之前也踩过坑!你用ddply能成但dplyr::mutate报错,核心原因是两者对多值结果的处理逻辑不一样:plyr::ddply在配合transform使用时,会自动把多值向量对应的组行进行扩展,而dplyr::mutate要求每个组生成的列长度必须和当前组的行数完全一致(你的每个id+HomeNum组都是1行,所以seq.Date返回的多值向量就触发了错误)。
下面给你三种纯dplyr生态的解决方案,都能输出tibble:
方案1:用mutate生成列表列 + unnest扩展行
这是比较经典的处理方式,先把每个组的月度序列存成列表列,再通过unnest把列表拆成多行:
library(dplyr) library(tidyr) library(tibble) # 你的示例数据 wide <- tibble( id = c(1, 1, 2, 2, 2), HomeNum = c(0,1,0,1,2), StartDate = as.Date(c("2001-01-01", "2001-03-01", "2000-04-01", "2001-02-01", "2002-08-01")), FinishDate = as.Date(c("2001-02-01", "2002-05-01", "2001-01-01", "2002-07-01", "2002-12-01")) ) panel <- wide %>% group_by(id, HomeNum) %>% # 用list()把序列包装成列表,避免长度不匹配错误 mutate(date = list(seq.Date(StartDate, FinishDate, by = "month"))) %>% # 把列表列拆成多行 unnest(date)
方案2:用reframe直接生成扩展结果
如果你用的是dplyr 1.0.0及以上版本,reframe是最简洁的选择——它允许每个组返回任意行数的结果,完美适配这种生成序列的场景:
panel <- wide %>% group_by(id, HomeNum) %>% reframe(date = seq.Date(StartDate, FinishDate, by = "month"))
方案3:用group_modify自定义组处理
如果你需要更灵活的组操作,可以用group_modify,它接收每个组的数据框,允许你返回一个新的数据框:
panel <- wide %>% group_by(id, HomeNum) %>% # .x代表当前组的数据框,从中提取起止日期生成序列 group_modify(~ tibble(date = seq.Date(.x$StartDate, .x$FinishDate, by = "month"))) %>% # 可选:取消分组,回到普通tibble ungroup()
补充:为什么ddply能正常运行?
ddply的transform参数在处理多值向量时,会自动将整个组的行重复对应次数,来匹配向量的长度,相当于帮你做了“隐式扩展”;而dplyr的设计更严谨,要求mutate的输出长度必须和输入组的行数一致,所以需要你显式地用unnest、reframe这类工具来完成行扩展的操作。
内容的提问来源于stack exchange,提问作者randy
相关产品推荐
相关产品推荐

