You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:03:25