如何基于另一DataFrame的列在目标DataFrame中生成指定规则的新列?
基于df2映射关系在df1中创建新列
需求说明
df1包含x、y、z三列,取值为0、1或NA;df2有a和b两列,其中b的取值包含df1的列名(还包含不存在的w)。需要根据df2中a与b的对应关系,在df1中创建以a的取值命名的新列:
- 当对应
a分组下任意存在于df1的b列在df1中的值为1时,新列值为1 - 若对应
a分组下的b列都不存在于df1(比如w),则新列值为0 - 计算时忽略NA值
示例数据
x <- c(1, 1, NA, NA, 0) y <- c(0, 1, 1, NA, NA) z <- c(1, 1, 0, 1, 1) df1 <- data.frame(x, y, z) a <- c( "Green", "Green", "Green", "Red", "Red", "Blue", "Blue", "Yellow") b <- c( "w", "x", "y", "x", "z", "w" , "y", "z" ) df2 <- data.frame(a, b)
期望输出
new_df1 x y z Green Red Blue Yellow 1 1 0 1 1 1 0 1 2 1 1 1 1 1 1 1 3 NA 1 0 1 0 1 0 4 NA NA 1 0 1 0 1 5 0 NA 1 0 1 0 1
解决方案
方法1:tidyverse工具链实现
通过转置数据格式、匹配映射关系、分组聚合的方式完成:
library(tidyverse) # 清理df2:仅保留df1中存在的列映射 df2_clean <- df2 %>% filter(b %in% colnames(df1)) # 生成新列:df1转长格式后匹配映射,按行和a分组判断是否有1 new_cols <- df1 %>% mutate(row_id = row_number()) %>% pivot_longer(-row_id, names_to = "b", values_to = "val") %>% inner_join(df2_clean, by = "b") %>% group_by(row_id, a) %>% summarise(val = as.integer(any(val == 1, na.rm = TRUE)), .groups = "drop") %>% pivot_wider(names_from = "a", values_from = "val", values_fill = 0) # 合并新列到原df1 new_df1 <- df1 %>% bind_cols(new_cols %>% select(-row_id)) print(new_df1)
方法2:base R原生实现
无需加载外部包,通过循环和逐行判断完成:
# 获取df2中a的唯一取值 a_unique <- unique(df2$a) # 初始化存储新列的列表 new_cols_list <- list() for (a_val in a_unique) { # 获取当前a对应的b列,过滤掉df1中不存在的列 b_cols <- df2$b[df2$a == a_val] b_cols <- b_cols[b_cols %in% colnames(df1)] if (length(b_cols) == 0) { # 无有效b列时,新列全为0 new_cols_list[[a_val]] <- rep(0, nrow(df1)) } else { # 逐行判断:是否有任意b列值为1(忽略NA) new_col <- apply(df1[, b_cols], 1, function(row) { as.integer(any(row == 1, na.rm = TRUE)) }) new_cols_list[[a_val]] <- new_col } } # 合并新列到原df1 new_df1 <- cbind(df1, do.call(cbind, new_cols_list)) print(new_df1)
内容的提问来源于stack exchange,提问作者Jaume
相关产品推荐
相关产品推荐

