R语言数据整理:长格式转宽格式(动态列实现难题)
解决方案
你可以通过拆分处理两类记录(REC="YES"和REC="NO")再合并的方式实现需求,具体代码如下:
library(dplyr) library(tidyr) # 处理原始数据并转换为目标宽格式 result <- A %>% group_by(ID) %>% # 为YES/NO类型的记录分别生成序号,用于动态列命名 mutate( rec_seq = if_else(REC == "YES", row_number()[REC == "YES"], NA_integer_), reop_seq = if_else(REC == "NO", row_number()[REC == "NO"], NA_integer_) ) %>% ungroup() %>% # 处理REC="YES"的记录,生成RECn_DATE列 pivot_wider( id_cols = c(ID, NR, INDX.DATE), names_from = rec_seq, values_from = REOP_DATE, names_prefix = "REC" ) %>% # 合并REC="NO"的处理结果 left_join( A %>% filter(REC == "NO") %>% group_by(ID) %>% mutate(reop_seq = row_number()) %>% ungroup() %>% # 找出TYPE列中值为1的对应编号(如TYPE3对应3) rowwise() %>% mutate(REOP_TYPE = which(c_across(starts_with("TYPE")) == 1)) %>% ungroup() %>% # 生成REOPn_DATE和REOPn_TYPE动态列 pivot_wider( id_cols = ID, names_from = reop_seq, values_from = c(REOP_DATE, REOP_TYPE), names_sep = "_" ), by = "ID" ) %>% # 填充同一ID的NR和INDX.DATE(原始数据仅第一行有值) group_by(ID) %>% mutate( NR = first(na.omit(NR)), INDX.DATE = first(na.omit(INDX.DATE)) ) %>% ungroup() %>% # 保留每个ID的唯一行 distinct(ID, .keep_all = TRUE) # 输出结果 print(result)
代码说明
- 标记序号:按ID分组后,为
REC="YES"的记录生成rec_seq序号,为REC="NO"的记录生成reop_seq序号,确保转宽时能生成带编号的动态列。 - 处理YES记录:通过
pivot_wider将REOP_DATE转换为REC1_DATE、REC2_DATE等列。 - 处理NO记录:先筛选出
REC="NO"的行,找出TYPE列中值为1的列对应的编号(如TYPE3值为1时,REOP_TYPE为3),再通过pivot_wider生成REOPn_DATE和REOPn_TYPE列。 - 合并与填充:将两部分结果按ID合并,填充同一ID的
NR和INDX.DATE值,最后去重得到每个ID的单行结果。
运行上述代码后,输出结果将完全匹配你需要的宽格式结构。
内容的提问来源于stack exchange,提问作者hklovs
相关产品推荐
相关产品推荐

