如何在R的tidyverse中按列唯一值生成新数据行(支持分组)
问题描述
原始数据集结构如下:
data <- data.frame( uniqueid = c(1, 1, 2, 2, 3, 3), year = c(2010, 2011, 2010, 2011, 2010, 2011), agency = c("SZ", "SZ", "SZ", NA, "SZ", "HE"), switch = c(0, 0, 0, NA, 0, 1) )
需求:按uniqueid和year分组,为agency列的每个唯一值生成新行,switch变量遵循以下逻辑:
- 与原始数据中该
uniqueid-year-agency匹配的行,保留原switch值; - 若原始数据中该
uniqueid-year的agency非NA,其他未匹配的agency对应的switch填0; - 若原始数据中该
uniqueid-year的agency为NA,所有agency对应的switch保留NA。
正确解决方案
使用tidyverse工具链实现,步骤如下:
- 加载tidyverse包并定义原始数据:
library(tidyverse) data <- data.frame( uniqueid = c(1, 1, 2, 2, 3, 3), year = c(2010, 2011, 2010, 2011, 2010, 2011), agency = c("SZ", "SZ", "SZ", NA, "SZ", "HE"), switch = c(0, 0, 0, NA, 0, 1) )
- 提取所有
agency的唯一值(包含NA):
all_agencies <- data %>% pull(agency) %>% unique()
- 生成目标结构数据:
result <- data %>% # 为每个uniqueid-year保存原始agency和switch值 group_by(uniqueid, year) %>% mutate(original_agency = agency, original_switch = switch) %>% ungroup() %>% select(uniqueid, year, original_agency, original_switch) %>% distinct() %>% # 为每个uniqueid-year组合匹配所有agency值 crossing(agency = all_agencies) %>% # 按逻辑设置switch值 mutate( switch = case_when( agency == original_agency ~ original_switch, !is.na(original_agency) ~ 0, TRUE ~ NA_real_ ) ) %>% # 移除辅助列并排序 select(-original_agency, -original_switch) %>% arrange(uniqueid, year, agency)
运行后得到的result即为需求的目标结构。
原代码问题说明
你之前的代码存在两处核心问题:
- 错误引用了不存在的
lead变量,应该使用switch; pivot_wider+gather的方式无法处理原始agency为NA时的特殊逻辑,也不能正确填充switch的缺失值。
内容的提问来源于stack exchange,提问作者sheri
相关产品推荐
相关产品推荐

