You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用dplyr基于df2批量替换df1多列中的NA值

问题

现有两个大型数据框df1(155列×3966行)与df2,二者首列均为ID,其余列名重叠。需求为:将df1中的NA值用df2对应位置的非NA值替换,无对应值则保留df1原数据。

示例数据

df1

> df1
       ID col1 col2  ...... col154
1  AMM115    C    A  ......     A+
2  ADM107   NA   NA  ......      B
3  AGM041    B    C  ......     C+
4  AGM132    A   NA  ......     A+
5  AQM007   NA    A  ......     B+
6  ARM028   NA   B+  ......     A-
7  ASM019    A   A+  ......     NA

df2

> df2
       ID col1 col2  ...... col154
1  ADM107   A+    B  ......      B
2  AGM041    C    A  ......     B+
3  ARM028   A+   B+  ......     NA
4  AQM007   B+    A  ......     B+

期望结果df3

> df3
       ID col1 col2  ...... col154
1  AMM115    C    A  ......     A+
2  ADM107   A+    B  ......      B
3  AGM041    B    C  ......     C+
4  AGM132    A   NA  ......     A+
5  AQM007   B+    A  ......     B+
6  ARM028   A+   B+  ......     A-
7  ASM019    A   A+  ......     NA

已尝试的代码

仅能处理单列,无法批量处理除ID外的所有列:

library(dplyr)
df1 %>% 
        left_join(df2, by = "ID") %>% 
        mutate(var2 = coalesce(var2.x, var2.y)) %>% 
        select(-var2.x, -var2.y)

解决方案

方法1:dplyr + across 批量处理

利用dplyr的across函数对所有非ID列批量应用coalesce,结合关联后的列名规则实现批量替换:

library(dplyr)
library(stringr)

# 关联两个数据框
df_joined <- df1 %>% left_join(df2, by = "ID")

# 批量替换并整理结果
df3 <- df_joined %>%
  mutate(
    across(
      .cols = matches("_x$"),
      .fns = ~ coalesce(., get(str_replace(cur_column(), "_x$", "_y"))),
      .names = "{str_remove(.col, '_x$')}"
    )
  ) %>%
  select(ID, all_of(setdiff(names(df1), "ID")))

方法2:data.table 高效处理(适合大型数据)

针对大尺寸数据,data.table的操作速度更优:

library(data.table)

# 转换为data.table格式
setDT(df1)
setDT(df2)

# 按ID关联并批量替换NA
df3 <- df1[df2, on = "ID"]
for (col in setdiff(names(df1), "ID")) {
  set(df3, 
      i = which(is.na(df3[[col]])), 
      j = col, 
      value = df3[[paste0(col, ".i")]]
  )
}

# 清理临时列
df3[, paste0(setdiff(names(df1), "ID"), ".i") := NULL]

方法3:base R 原生实现

无需额外依赖包,用原生函数完成替换:

# 匹配df2对应df1的行索引
matched_rows <- match(df1$ID, df2$ID)

# 遍历所有非ID列替换NA
for (col in setdiff(names(df1), "ID")) {
  na_idx <- is.na(df1[[col]])
  df1[na_idx, col] <- df2[matched_rows[na_idx], col]
}

df3 <- df1

内容的提问来源于stack exchange,提问作者Roq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 02:06:04