如何在R中合并(merge)并聚合(coalesce)多个数据框?
解决多数据集合并时NA覆盖有效数值的问题
问题场景
你有多个经长转宽得到的数据集,示例数据如下:
data1 <- data.frame( x1 = c(1, NA, NA, NA, NA, NA), x2 = c(NA, 1, NA, NA, NA, NA), x3 = c(NA, NA, NA, 1, 1, NA), y = 11:16, z = 6:1) data2 <- data.frame( x1 = c(NA, NA, 2, 2, NA, NA), x2 = c(NA, NA, NA, NA, 2, NA), x4 = c(NA, NA, NA, NA, NA, 2), y = 11:16, z = 6:1) data3 <- data.frame( x2 = c(3, NA, 3, NA, NA, NA), x3 = c(NA, 3, NA, NA, NA, NA), x5 = c(NA, NA, NA, NA, 3, 3), y = 11:16, z = 6:1)
这些数据集的特点:
- 所有数据集行数相同
y、z列在所有数据集中均存在且完全一致,可作为行标识符- 其他列仅存在于部分数据集,包含大量NA和少量有效数值,部分列(如
x1、x2)存在于多个数据集
你需要合并所有数据集,保留所有列,并用任意数据集中的有效数值替换对应列的NA,预期结果如下:
datafull x1 x2 x3 x4 x5 y z 1 1 3 NA NA NA 11 6 2 NA 1 3 NA NA 12 5 3 2 3 NA NA NA 13 4 4 2 NA 1 NA NA 14 3 5 NA 2 1 NA 3 15 2 6 NA NA NA 2 3 16 1
你尝试的错误方法
你用merge结合Reduce处理,但新增数据集的NA覆盖了原有有效数值:
datasetlist <- list(data1, data2, data3) datafull <- Reduce(function(x, y) merge(x, y, all.y=TRUE), datasetlist)
得到错误结果:
datafull x2 y z x3 x1 x4 x5 1 3 11 6 NA NA NA NA 2 3 13 4 NA NA NA NA 3 NA 12 5 3 NA NA NA 4 NA 14 3 NA 2 NA NA 5 NA 15 2 NA NA NA 3 6 NA 16 1 NA NA 2 3
解决方案
方法一:基于行标识符的全连接+NA填充
利用dplyr的full_join按y、z匹配行,再用coalesce函数合并同列的非NA值:
library(dplyr) datasetlist <- list(data1, data2, data3) # 定义自定义合并函数 merge_with_coalesce <- function(x, y) { # 按y和z做全连接 joined_df <- full_join(x, y, by = c("y", "z")) # 获取除y、z外的共同列名 common_cols <- setdiff(intersect(names(x), names(y)), c("y", "z")) # 对每个共同列,用coalesce合并非NA值,删除临时列 for(col in common_cols) { joined_df[[col]] <- coalesce(joined_df[[paste0(col, ".x")]], joined_df[[paste0(col, ".y")]]) joined_df <- joined_df %>% select(-all_of(paste0(col, c(".x", ".y")))) } return(joined_df) } # 合并所有数据集 datafull <- Reduce(merge_with_coalesce, datasetlist) # 调整列顺序(可选) datafull <- datafull %>% select(x1, x2, x3, x4, x5, y, z)
方法二:利用行顺序一致的特性快速合并
因为所有数据集行数相同且行顺序完全对应,可直接按列收集后合并非NA值:
library(dplyr) library(purrr) datasetlist <- list(data1, data2, data3) # 获取所有唯一列名 all_column_names <- unique(unlist(map(datasetlist, names))) # 对每个列,从所有数据集中提取并合并非NA值 datafull <- map_dfc(all_column_names, function(col) { # 收集该列在所有数据集中的值,无对应列则填充NA column_data <- map_dfc(datasetlist, ~.x[[col]] %||% NA) # 每行取第一个非NA值 coalesce(!!!column_data) }) %>% set_names(all_column_names) # 调整列顺序(可选) datafull <- datafull %>% select(x1, x2, x3, x4, x5, y, z)
两种方法都能得到你预期的合并结果,避免NA覆盖有效数值的问题。
内容的提问来源于stack exchange,提问作者Silvia
相关产品推荐
相关产品推荐

