在R中合并行数相同、列不同的多个dataframe
在R中合并多个同行数、异列的DataFrame(共享键列)
问题说明
需要合并多个行数相同、列不同的DataFrame,它们共享x列作为键,期望得到行数与原DataFrame一致(如示例中的3行)、包含所有列的结果。但使用map_df读取并合并文件时,得到的是行堆叠且带大量NA的错误输出。
示例数据
df1 <- data.frame( x = c("A1", "A2", "A3"), y = c(1, 2, 3)) df2 <- data.frame( x = c("A1", "A2", "A3"), z = c(4, 5, 6)) df3 <- data.frame( x = c("A1", "A2", "A3"), a = c(7, 8, 9)) df4 <- data.frame( x = c("A1", "A2", "A3"), b = c(10, 11, 12))
错误代码及输出
错误代码:
files_list <- list.files("files", full.names = TRUE) dfs <- files_list %>% map_df(~read_csv(.x))
错误输出:
x y z a b 1 A1 1 NA NA NA 2 A2 2 NA NA NA 3 A3 3 NA NA NA 4 A1 NA 4 NA NA 5 A2 NA 5 NA NA 6 A3 NA 6 NA NA 7 A1 NA NA 7 NA 8 A2 NA NA 8 NA 9 A3 NA NA 9 NA 10 A1 NA NA NA 10 11 A2 NA NA NA 11 12 A3 NA NA NA 12
解决方案
方法1:Tidyverse工具链(推荐)
map_df本质是按行堆叠数据,而我们需要的是基于共享键x的列合并。先将文件读取为DataFrame列表,再用reduce逐个合并:
library(dplyr) library(purrr) files_list <- list.files("files", full.names = TRUE) # 读取为DataFrame列表,而非直接行绑定 dfs_list <- map(files_list, ~read_csv(.x)) # 按x列合并所有DataFrame merged_df <- dfs_list %>% reduce(inner_join, by = "x")
如果能确保所有DataFrame的行顺序完全与x列对应,也可以用bind_cols快速合并(需清理重复的x列):
merged_df <- dfs_list %>% bind_cols() %>% select(-matches("x\\.\\d+")) # 移除重复的x列
方法2:Base R实现
无需加载tidyverse包,用Reduce和merge函数即可完成:
files_list <- list.files("files", full.names = TRUE) # 根据文件格式选择read.csv或read.table dfs_list <- lapply(files_list, read.csv) merged_df <- Reduce(function(x, y) merge(x, y, by = "x"), dfs_list)
错误原因
map_df是bind_rows的批量封装,它会将所有输入的DataFrame按行堆叠,因此4个3行的DataFrame会被拼接成12行,缺失的列自动填充NA,这与按键合并的需求逻辑不符。
内容的提问来源于stack exchange,提问作者Karina
相关产品推荐
相关产品推荐

