使用dplyr的group_by移除含多NA行并合并p_id唯一行
解决按p_id合并行并移除多余NA的问题
嘿,这需求很常见,我来给你两个靠谱的解决方案,不管你用dplyr还是base R都能搞定,而且支持任意列数哦!
先看你的原始数据
首先把你的测试数据放出来,方便对照:
df <- data.frame(id=c(1,1,2,3,4,4),p_id=c(1001,1001,1002,1003,1004,1004),x=c(1,NA,1,2,NA,1),y=c(NA,5,4,NA,6,NA),z=c(NA,NA,2,3,NA,4))
对应的表格:
| id | p_id | x | y | z |
|---|---|---|---|---|
| 1 | 1001 | 1 | NA | NA |
| 1 | 1001 | NA | 5 | NA |
| 2 | 1002 | 1 | 4 | 2 |
| 3 | 1003 | 2 | NA | 3 |
| 4 | 1004 | NA | 6 | NA |
| 4 | 1004 | 1 | NA | 4 |
方案一:用dplyr(推荐,代码更直观)
如果你习惯用tidyverse系列工具,这个方案最顺手,扩展性拉满,加多少列都不用改代码:
library(dplyr) # 核心处理代码 result <- df %>% group_by(p_id) %>% # 对除id外的所有列处理,自动适配任意列数 summarise(across(-id, ~{ non_na_vals <- na.omit(.x) if (length(non_na_vals) > 0) non_na_vals[1] else NaN }), .groups = "drop") # 查看结果 print(result)
代码解释
group_by(p_id):把相同p_id的行归为一组,这是合并的基础across(-id, ...):指定要处理的列,-id表示排除id列,剩下的所有列(不管是x、y、z还是以后新增的列)都会被处理,完美支持任意列数- 自定义函数逻辑:对每组的列数据,先过滤掉NA值,如果有非NA值就取第一个(你的数据里每组同一列只有一个非NA值),如果全是NA就返回NaN,和你期望的输出完全匹配
.groups = "drop":处理完后取消分组结构,得到普通的数据框
方案二:用base R(无需额外安装包)
如果不想加载dplyr,用base R的aggregate函数也能实现:
# base R 版本代码 result_base <- aggregate(. ~ p_id, data = df[, -1], FUN = function(x) { non_na_vals <- na.omit(x) if (length(non_na_vals) > 0) non_na_vals[1] else NaN }) # 查看结果 print(result_base)
代码解释
aggregate(. ~ p_id, data = df[, -1], ...):按p_id分组,对df[, -1](去掉id列后的所有数据)应用自定义函数- 自定义函数的逻辑和dplyr版本完全一致,最终效果也相同
最终输出结果
不管用哪个方案,你都会得到想要的结果:
| p_id | x | y | z |
|---|---|---|---|
| 1001 | 1 | 5 | NaN |
| 1002 | 1 | 4 | 2 |
| 1003 | 2 | NaN | 3 |
| 1004 | 1 | 6 | 4 |
内容的提问来源于stack exchange,提问作者SinghD
相关产品推荐
相关产品推荐

