使用lag()向下填充NA仅生效一次,无法填充整列的原因咨询
问题:向下填充NA值的代码为何仅生效一次?
我有一组仅在序列首行有值的数据,示例代码如下:
data <- data_frame(no = c(1:10), day = c("day 1", NA, NA, NA, "day2", NA, NA, "day3", NA, NA))
原始数据展示:
no day <int> <chr> 1 1 day 1 2 2 NA 3 3 NA 4 4 NA 5 5 day2 6 6 NA 7 7 NA 8 8 day3 9 9 NA 10 10 NA
我希望将day列的有效值向下填充,直到出现新值,目标结果如下:
no day <int> <chr> 1 1 day 1 2 2 day 1 3 3 day 1 4 4 day 1 5 5 day2 6 6 day2 7 7 day2 8 8 day3 9 9 day3 10 10 day3
我尝试用以下代码实现:
data <- data %>% mutate(day = if_else(is.na(day), lag(day), day))
但结果仅填充了每个NA序列的第一个值:
no day <int> <chr> 1 1 day 1 2 2 day 1 3 3 NA 4 4 NA 5 5 day2 6 6 day2 7 7 NA 8 8 day3 9 9 day3 10 10 NA
我原本以为计算第三行时,第二行已经被填充了第一行的值,但实际并非如此。尝试用is.null/is_null替代is.na会报错,用day = day %||% lag(day)也无效果。我已找到zoo::na.locf()可以实现需求,但仍想了解自己的代码为何失效。
解答
你的代码失效的核心原因是:dplyr的mutate函数基于列的原始值计算,不会逐行更新并复用修改后的值。
具体来说,lag(day)调用的始终是原始day列的上一行值,而非mutate过程中刚修改好的新值:
- 第二行的
day是NA,取原始第一行的day 1填充,这步正常; - 第三行的
day是NA,此时lag(day)取的是原始第二行的NA,而非修改后的第二行的day 1,所以第三行仍为NA; - 后续NA行同理,只能取到原始数据中上一行的NA,无法实现连续填充。
如果不想依赖zoo包,用dplyr也能实现需求:通过创建分组标识,把每个有效值到下一个有效值前的行归为一组,再用每组的第一个有效值填充整组:
data <- data %>% # 创建分组:每遇到非NA值就新建一组 group_by(grp = cumsum(!is.na(day))) %>% # 用每组第一个非NA值填充整组的day列 mutate(day = first(day)) %>% ungroup() %>% # 移除临时分组列 select(-grp)
内容的提问来源于stack exchange,提问作者Radek Jaźwiec
相关产品推荐
相关产品推荐

