如何使用tidyr::fill将NA填充为倒数第二个非NA值?
解决方案
核心思路
由于tidyr::fill只能按最近的非NA值填充,无法直接指定“倒数第二个非NA值”,我们可以通过分组标记+组内提取目标值的方式实现需求:
- 先完成
amount/amount_thismkt/nation列的常规向下填充; - 以
amount列的非NA行为分组依据,生成组ID; - 在每个组内提取倒数第二个非NA的
purpose值(若组内仅1个非NA值则直接取用),用该值填充组内的NA条目。
完整代码
library(tidyverse) df <- tibble(amount = c(2000, NA, NA, NA, 2500, NA, NA, NA), amount_thismkt = c(1000, NA, NA, NA, 2500, NA, NA, NA), nation = c("United States", NA, NA, NA, "China", NA, NA, NA), purpose = c("Refinancing", "GCP", NA, NA, "GCP", "Refinancing", NA, NA), bank = c("A", "B", "C", "D", "A", "E", "F", "B")) df_final <- df %>% # 先处理其他列的常规填充 fill(amount, amount_thismkt, nation) %>% # 按amount的非NA行生成分组ID mutate(group_id = cumsum(!is.na(amount))) %>% group_by(group_id) %>% mutate( # 提取组内所有非NA的purpose值 purpose_non_na = na.omit(purpose), # 确定填充值:非NA值>=2则取倒数第二个,否则取唯一值 fill_value = if (length(purpose_non_na) >= 2) { purpose_non_na[length(purpose_non_na) - 1] } else { purpose_non_na[1] }, # 替换NA值 purpose = ifelse(is.na(purpose), fill_value, purpose) ) %>% ungroup() %>% # 移除临时辅助列 select(-group_id, -purpose_non_na, -fill_value) # 查看结果 df_final
输出结果
# A tibble: 8 × 5 amount amount_thismkt nation purpose bank <dbl> <dbl> <chr> <chr> <chr> 1 2000 1000 United States Refinancing A 2 2000 1000 United States GCP B 3 2000 1000 United States Refinancing C 4 2000 1000 United States Refinancing D 5 2500 2500 China GCP A 6 2500 2500 China Refinancing E 7 2500 2500 China GCP F 8 2500 2500 China GCP B
说明
- 分组逻辑:通过
cumsum(!is.na(amount))生成连续的组ID,确保每个“标题行(amount非NA)”到下一个标题行之前的记录属于同一组; - 填充逻辑:针对每个组,先筛选出所有非NA的
purpose值,当存在至少2个非NA值时取倒数第二个,否则直接取用唯一的非NA值,再用该值替换组内的NA条目; - 保留原非NA值:仅替换
purpose列的NA,原有的非NA条目(如行2的GCP、行6的Refinancing)会被保留。
内容的提问来源于stack exchange,提问作者lyd-m
相关产品推荐
相关产品推荐

