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

如何使用fill()函数按条件填充NA值(无需循环)

分组填充NA值的解决方案

嘿,我明白你遇到的问题了——你有按caseid分组的时间序列数据,想把每组里caseval的NA用上一行的有效值填充,但之前试的方法都没生效对吧?大概率是没做分组操作导致的,直接整列填充会跨组乱填,咱们来解决这个问题。

首先先把你的示例数据整理成可运行的代码,方便测试:

# 构造你提到的示例数据
casedate <- seq(as.Date('2018/1/1'), as.Date('2018/3/5'), by='week')
caseid <- c(rep(1,10), rep(2,10), rep(3,10))
caseval <- c(80, rep(NA,4), rep(80,5), 
             40, rep(NA,2), rep(40,4), rep(NA,3), 
             60, rep(NA,3), rep(60,6))
df <- data.frame(casedate, caseid, caseval)

下面是三个靠谱的解决方案,选你顺手的用就行:

方案1:用tidyverse的fill()(最直观,新手友好)

tidyverse里的fill()就是专门干这个的,配合group_by()锁定每个caseid分组,就能实现组内填充:

library(tidyverse)

# 分组后向下填充NA(用上一行的有效值填后面的空)
df_filled <- df %>%
  group_by(caseid) %>%
  fill(caseval, .direction = "down") %>% # direction控制填充方向
  ungroup()

要是你需要双向填充(比如中间NA,前后都有有效值),把.direction改成"downup"就行。

方案2:用data.table的nafill()(大数据首选,速度快)

如果你的数据量很大,data.table的方法性能会好很多,而且代码也简洁:

library(data.table)

setDT(df) # 把数据转成data.table格式
df_filled <- df[, caseval := nafill(caseval, type = "locf"), by = caseid]

这里type = "locf"是“last observation carried forward”的缩写,意思就是用最近的上一个有效值填充,和上面fill的down方向效果一样。

方案3:Base R原生方法(不用装额外包)

要是不想加载第三方库,用base R的ave()也能实现:

df_filled <- df
df_filled$caseval <- ave(df_filled$caseval, df_filled$caseid, 
                         FUN = function(x) {
                           # 先找到组内所有非NA的位置
                           non_na_pos <- which(!is.na(x))
                           # 给每个位置匹配对应的非NA值
                           x[non_na_pos[cumsum(!is.na(x))]]
                         })

你可以运行完代码后打印df_filled看看,每个caseid分组里的NA都会被前面的有效值正确填充,不会跨组乱套。

内容的提问来源于stack exchange,提问作者Dan Blanchard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:35:50