在R语言中如何将instance为NA的分组行合并为单行?
问题描述
现有如下R数据框:
df <- data.frame( record_id = c(1, 1, 1, 2, 2, 3, 3, 3), instance = c(NA, NA, 2, NA, 1, 2, NA, NA), A = c(10, NA, NA, 20, 25, NA, 30, NA), B = c(NA, 5, NA, NA, 5, 15, NA, 15), C = c(NA, NA, 3, NA, 5, 20, NA, 20), D = c(NA, NA, NA, 25, 25, 30, NA, 30) )
数据预览:
record_id instance A B C D 1 1 NA 10 NA NA NA 2 1 NA NA 5 NA NA 3 1 2 NA NA 3 NA 4 2 NA 20 NA NA 25 5 2 1 25 5 5 25 6 3 2 NA 15 20 30 7 3 NA 30 NA NA NA 8 3 NA NA 15 20 30
需求:把同一record_id下instance为NA的行合并成单行(已知同一分组内同一列不会有多个非NA值),最终期望结果如下:
record_id instance A B C D 1 1 NA 10 5 NA NA 2 1 2 NA NA 3 NA 3 2 NA 20 NA NA 25 4 2 1 25 5 5 25 5 3 2 NA 15 20 30 6 3 NA 30 15 20 30
解决方案
方法一:用dplyr包实现
核心逻辑是给instance为NA的行统一分组标记,让同一record_id下的NA行归为一组,然后对每组的每列提取唯一的非NA值,最后还原instance列格式:
library(dplyr) df_result <- df %>% # 生成分组键:NA的instance归为同一组,非NA保留原值 mutate(group_key = ifelse(is.na(instance), "NA_group", as.character(instance))) %>% group_by(record_id, group_key) %>% # 对每列取第一个非NA值(同一组同一列仅一个有效数据) summarise(across(everything(), ~ first(na.omit(.x))), .groups = "drop") %>% # 将分组键转换回原instance格式 mutate(instance = ifelse(group_key == "NA_group", NA, as.numeric(group_key))) %>% # 调整列顺序并排序,和示例结果一致 select(record_id, instance, A, B, C, D) %>% arrange(record_id, instance) print(df_result)
方法二:用data.table包实现(大数据量更高效)
逻辑和dplyr一致,适合处理大规模数据集:
library(data.table) setDT(df) df_result <- df[, lapply(.SD, function(x) first(na.omit(x))), by = .(record_id, group_key = ifelse(is.na(instance), "NA_group", as.character(instance))) ][, instance := fifelse(group_key == "NA_group", NA_real_, as.numeric(group_key)) ][, .(record_id, instance, A, B, C, D) ][order(record_id, instance)] print(df_result)
内容的提问来源于stack exchange,提问作者Andrea
相关产品推荐
相关产品推荐

