使用tidyverse替换tibble中NA值为子节点value之和并保留原值
问题
现有如下tibble数据框,需将其中的NA值替换为对应子节点的value之和(例:c的value为d+e的和,a的value为b+c的和),同时保留非NA的原始值:
library(tibble) mydata <- tibble(id = c("a", "b", "c", "d", "e"), value = c(NA, 1, NA, 2, 3), parent = c(NA, "a", "a", "c", "c"), level = c(1,2,2,3,3))
原始数据展示:
# A tibble: 5 x 4 id value parent level <chr> <dbl> <chr> <dbl> 1 a NA NA 1 2 b 1 a 2 3 c NA a 2 4 d 2 c 3 5 e 3 c 3
期望输出:
id value parent level <chr> <dbl> <chr> <dbl> 1 a 6 NA 1 2 b 1 a 2 3 c 5 a 2 4 d 2 c 3 5 e 3 c 3
已尝试部分方法但流程繁琐,希望用tidyverse实现简洁方案,原问题涉及5个层级,是否需要循环?
解决方案
可以利用从底层到顶层的计算逻辑,结合dplyr的分组汇总与连接操作,无需显式写多层逻辑,代码适配任意层级:
library(tidyverse) result <- mydata # 按层级从高到低处理(先算最底层,再逐层往上更新父节点) for (current_level in sort(unique(result$level), decreasing = TRUE)) { # 计算当前层级节点对应的父节点的子节点总和 child_totals <- result %>% filter(level == current_level) %>% group_by(parent) %>% summarize(child_sum = sum(value, na.rm = TRUE), .groups = "drop") # 将总和匹配到父节点,替换NA值 result <- result %>% left_join(child_totals, by = c("id" = "parent")) %>% mutate(value = coalesce(value, child_sum)) %>% select(-child_sum) } print(result)
核心逻辑说明
- 遍历顺序:按
level降序遍历,确保底层节点的value先被确定,上层父节点计算时能直接使用已更新的子节点值。 - 分组求和:对每个层级的节点,按
parent分组计算子节点的value总和。 - 值替换:用
coalesce()函数直接替换NA值(比ifelse更简洁),保留原始非NA值。
这个方法可以无缝适配5个层级的场景,不需要针对每个层级单独编写逻辑,扩展性强。
内容的提问来源于stack exchange,提问作者arnyeinstein
相关产品推荐
相关产品推荐

