在R中按组补全日期与值,保留原始NA
按组补全日期并保留原始NA的后续空值需求
原始数据
原始数据框df如下:
group date value 1 A 2022-12-01 1 2 A 2022-12-03 3 3 A 2022-12-06 NA 4 A 2022-12-08 1 5 B 2022-12-01 2 6 B 2022-12-05 2 7 C 2022-12-01 4 8 C 2022-12-06 NA 9 C 2022-12-08 6
dput代码:
df <- structure(list(group = c("A", "A", "A", "A", "B", "B", "C", "C", "C"), date = structure(c(1669849200, 1670022000, 1670281200, 1670454000, 1669849200, 1670194800, 1669849200, 1670281200, 1670454000 ), class = c("POSIXct", "POSIXt"), tzone = ""), value = c(1, 3, NA, 1, 2, 2, 4, NA, 6)), class = "data.frame", row.names = c(NA, -9L))
预期输出
按组补全日期后,需保留原始NA,且该NA之后的补全行也保持NA,预期结果如下:
group date value 1 A 2022-12-01 1 2 A 2022-12-02 1 3 A 2022-12-03 3 4 A 2022-12-04 3 5 A 2022-12-05 3 6 A 2022-12-06 NA 7 A 2022-12-07 NA 8 A 2022-12-08 1 9 B 2022-12-01 2 10 B 2022-12-02 2 11 B 2022-12-03 2 12 B 2022-12-04 2 13 B 2022-12-05 2 14 C 2022-12-01 4 15 C 2022-12-02 4 16 C 2022-12-03 4 17 C 2022-12-04 4 18 C 2022-12-05 4 19 C 2022-12-06 NA 20 C 2022-12-07 NA 21 C 2022-12-08 6
需求关键点
- 按
group分组,补全每组内从最小日期到最大日期的所有单日日期 - 补全日期对应的
value需遵循:- 原始非NA值的前后补全行用前向填充
- 原始NA需保留,且该NA之后的所有补全行(直到下一个原始非NA值)均保持NA
用户尝试的问题
- 仅使用
complete补全日期,补全行的value均为NA,未实现填充:
library(dplyr) library(tidyr) df %>% group_by(group) %>% complete(., date = seq(min(date), max(date), by = 'day', fill = list(value = NA)))
- 添加
fill函数后,原始NA被填充为前值,破坏原始数据:
df %>% group_by(group) %>% complete(., date = seq(min(date), max(date), by = 'day', fill = list(value = NA))) %>% fill(value, .direction = 'down')
解决方案
通过保存原始值、前向填充后恢复原始NA及后续空值的方式实现:
library(dplyr) library(tidyr) df %>% group_by(group) %>% # 补全每组内的所有单日日期 complete(date = seq(min(date), max(date), by = "day")) %>% # 保存原始value,标记原始NA位置 mutate(original_value = value) %>% # 前向填充所有空值 fill(value, .direction = "down") %>% # 标记从第一个原始NA开始的所有行 mutate(has_occured_na = cumany(is.na(original_value))) %>% # 恢复原始NA及之后补全行的空值 mutate(value = ifelse(has_occured_na & is.na(original_value), NA, value)) %>% # 移除辅助列 select(-original_value, -has_occured_na) %>% ungroup()
代码说明
complete:按组补全日期区间内的所有单日日期mutate(original_value = value):保存原始value,避免填充后丢失原始NA的位置信息fill(value, .direction = "down"):前向填充所有空值,包括原始NA和补全产生的NAmutate(has_occured_na = cumany(is.na(original_value))):标记从第一个原始NA开始的所有行,确保后续行都被识别为需保留空值的区间mutate(value = ifelse(...)):对已出现原始NA的行,若为原始NA或补全产生的NA则恢复为空值,原始非NA值保留填充结果select:移除辅助列,得到最终结果
内容的提问来源于stack exchange,提问作者Quinten
相关产品推荐
相关产品推荐

