如何在R数据框中基于两个ID列生成0-1虚拟变量?
解决R数据框中基于多列ID生成0-1虚拟列的问题
需求说明
现有包含ID1和ID2两列的R数据框,需要为所有唯一ID生成对应的0-1虚拟列:当某行的ID1或ID2等于该唯一ID时,对应列值为1,否则为0。
示例数据与预期结果
# 原始数据 df <- data.frame(ID1=c("TEST1", "TEST2", "TEST3", "TEST4"), ID2=c("TEST2", "TEST3", "TEST4", "TEST5")) # 预期结果 data.frame(ID1=c("TEST1", "TEST2", "TEST3", "TEST4"), ID2=c("TEST2", "TEST3", "TEST4", "TEST5"), TEST1=c(1, 0, 0, 0), TEST2=c(1, 1, 0, 0), TEST3=c(0, 1, 1, 0), TEST4=c(0, 0, 1, 1), TEST5=c(0, 0, 0, 1))
原方法问题分析
你之前尝试分别对ID1和ID2做pivot_wider再连接的思路,会导致相同ID的列出现重复(如TEST2.x、TEST2.y),且合并时无法直接将两个列的1值合并,反而增加了处理复杂度。
解决方案
方法1:使用tidyverse一站式处理
通过先转长格式标记ID出现,再转回宽格式生成虚拟列,最后合并原数据,步骤简洁且避免重复列问题:
library(tidyverse) result <- df %>% # 添加行号用于后续匹配原行 mutate(row_id = row_number()) %>% # 将ID1、ID2转为长格式,统一处理所有ID pivot_longer(cols = c(ID1, ID2), values_to = "id") %>% # 标记出现的ID为1 mutate(value = 1) %>% # 转回宽格式,缺失值填充为0 pivot_wider(id_cols = row_id, names_from = id, values_from = value, values_fill = 0) %>% # 合并原数据并清理临时列 left_join(df, by = "row_id") %>% select(-row_id) %>% # 调整列顺序,将原ID列置于最前 select(ID1, ID2, everything()) print(result)
方法2:基础R实现
无需加载额外包,直接通过提取唯一ID并逐列判断生成虚拟列:
# 获取所有唯一ID unique_ids <- unique(c(df$ID1, df$ID2)) # 为每个ID生成0-1列:判断每行ID1/ID2是否等于当前ID dummy_cols <- sapply(unique_ids, function(id) { as.integer(df$ID1 == id | df$ID2 == id) }) # 合并原数据与虚拟列 result <- cbind(df, dummy_cols) print(result)
方法3:使用fastDummies包简化操作
借助fastDummies的虚拟列生成功能,适合更复杂的ID场景:
library(fastDummies) library(tidyverse) result <- df %>% mutate(row_id = row_number()) %>% # 转长格式统一处理ID pivot_longer(cols = c(ID1, ID2), values_to = "id") %>% # 生成ID对应的虚拟列 dummy_cols(select_columns = "id", remove_selected_columns = TRUE) %>% # 按行聚合,保留最大的1值(同一行同一ID可能在ID1/ID2都出现) group_by(row_id) %>% summarise(across(starts_with("id_"), max)) %>% # 合并原数据并清理列名 left_join(df, by = "row_id") %>% select(-row_id) %>% rename_with(~gsub("id_", "", .), starts_with("id_")) %>% select(ID1, ID2, everything()) print(result)
内容的提问来源于stack exchange,提问作者Mallory Feldman
相关产品推荐
相关产品推荐

