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

复杂场景下合并DataFrame:冲突值随机选择的实现求助

合并互补数据集并处理冲突值

问题说明

我有两个理论上应包含互补缺失信息但存在错误的数据集,需合并到主DataFrame「df」中。理论上,若ID x在df1中存在年份y、变量z的数据,则该ID在df2中不应有对应值,但实际存在两者均有值的冲突情况。需要生成前缀为「apcs」、格式与df1和df2一致的新变量:仅其中一个数据集有值时取该值,两者均有值时随机选择其一。

模拟数据

library(dplyr)

set.seed(123) # 设定随机种子保证结果可复现
df <- data.frame(id = c(1:20),
                 og_var1 = sample(c(1:50), 20, replace=TRUE),
                 state = sample(c(1:52), 20, replace=TRUE),
                 race = sample(c(1:5), 20, replace=TRUE)
)

df1 <- left_join(data.frame(id = (1:20)), data.frame(
  id =              c(3,6,9,12),
  acs09_married =   c(1,NA,2,1),
  acs09_happiness = c(1,NA,3,2),
  acs10_married =   c(NA,1,2,2),
  acs10_happiness = c(NA,5,2,5)), by=c("id"))

df2 <- left_join(data.frame(id = (1:20)), data.frame(
  id =              c(3,6,11,15),
  pcs09_married =   c(NA,1,1,1),
  pcs09_happiness = c(NA,3,3,2),
  pcs10_married =   c(1,2,2,1),
  pcs10_happiness = c(2,5,4,4)), by=c("id"))

原尝试代码(存在问题)

df <- left_join(df, df1, by=c("id"))
df <- left_join(df, df2, by=c("id"))

df$random <- sample(0:1, size=nrow(df), replace =TRUE)

years=c("09", "10")

list <- colnames(df %>% select(contains(c("var", "prcs"))))
list <- sub(".*_", "", x)     
list <- unique(x)
list

for(x in years){
  for(j in list){
  df <- df %>% mutate(paste0("apcs",x,"_",j) =
                        ifelse(
                          !is.na(get(paste0("acs",x,"_",j))) &
                          !is.na(get(paste0("pcs",x,"_",j))), ifelse(random = 1,
                                                                     get(paste0("acs",x,"_",j)),
                                                                     get(paste0("pcs",x,"_",j))), NA
                        )
                      )
  }
}

简便解决方案

方法一:长格式转换处理(简洁直观)

通过宽转长分组处理冲突,再转回宽格式,避免复杂循环:

library(tidyr)

# 合并所有数据到主df
df_combined <- df %>% 
  left_join(df1, by = "id") %>% 
  left_join(df2, by = "id")

# 生成apcs变量并处理冲突
df_final <- df_combined %>%
  # 拆分acs/pcs变量为来源、年份、变量名三部分
  pivot_longer(
    cols = starts_with(c("acs", "pcs")),
    names_to = c("source", "year", "var"),
    names_pattern = "(acs|pcs)(\\d{2})_(.*)",
    values_to = "value"
  ) %>%
  # 按ID、年份、变量分组
  group_by(id, year, var) %>%
  # 过滤缺失值
  filter(!is.na(value)) %>%
  # 冲突时随机选1个值,非冲突时保留唯一值
  slice_sample(n = 1) %>%
  ungroup() %>%
  # 将来源标记改为apcs
  mutate(source = "apcs") %>%
  # 转回宽格式得到apcs前缀变量
  pivot_wider(
    names_from = c(source, year, var),
    names_sep = "",
    values_from = value
  ) %>%
  # 合并回原始数据,保留所有变量
  right_join(df_combined, by = "id") %>%
  # 调整列顺序(可选)
  select(id, og_var1, state, race, starts_with("apcs"), everything())

方法二:动态变量赋值循环(保留宽格式)

如果偏好直接在宽格式下处理,可使用动态变量名实现:

library(stringr)

# 合并数据
df_combined <- df %>% 
  left_join(df1, by = "id") %>% 
  left_join(df2, by = "id")

# 提取目标变量名(married、happiness)
target_vars <- df_combined %>%
  select(starts_with("acs")) %>%
  colnames() %>%
  str_remove("acs\\d{2}_") %>%
  unique()

years <- c("09", "10")

# 生成每行随机选择标记(1选acs,2选pcs)
df_final <- df_combined %>%
  mutate(random_flag = sample(c(1, 2), n(), replace = TRUE))

# 循环生成每个apcs变量
for (year in years) {
  for (var in target_vars) {
    acs_col <- paste0("acs", year, "_", var)
    pcs_col <- paste0("pcs", year, "_", var)
    apcs_col <- paste0("apcs", year, "_", var)
    
    df_final <- df_final %>%
      mutate(
        !!apcs_col := case_when(
          !is.na(.data[[acs_col]]) & is.na(.data[[pcs_col]]) ~ .data[[acs_col]],
          is.na(.data[[acs_col]]) & !is.na(.data[[pcs_col]]) ~ .data[[pcs_col]],
          !is.na(.data[[acs_col]]) & !is.na(.data[[pcs_col]]) ~ ifelse(random_flag == 1, .data[[acs_col]], .data[[pcs_col]]),
          TRUE ~ NA_real_
        )
      )
  }
}

# 移除临时随机标记列
df_final <- df_final %>% select(-random_flag)

原代码问题说明

  1. 变量提取错误:select(contains(c("var", "prcs")))应改为contains(c("acs", "pcs")),且sub(".*_", "", x)中的x未定义,需替换为list。
  2. 动态赋值错误:mutate中不能直接用paste0(...) = ...,需使用!!apcs_col := ...的动态赋值语法。
  3. 逻辑判断错误:ifelse(random = 1是赋值操作,应为ifelse(random == 1。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 17:42:00