在R中基于两个变量将同一ID的多行合并为一行多列
解决方案:使用tidyverse工具实现格式转换
不需要使用for循环,借助dplyr和tidyr包可以高效完成这种分组宽展的需求,具体步骤如下:
1. 加载依赖包
library(tidyverse)
2. 预处理数据:给日期和诊断编序号
首先为每个患者的不同就诊日期分配序号,同时为同一日期下的多个诊断分配序号,这是后续宽展的基础:
df_processed <- df %>% # 转换日期格式确保排序准确性(若原日期字符串排序逻辑正确可省略) mutate(dx_date = as.Date(dx_date, format = "%m/%d/%y")) %>% group_by(id) %>% # 为每个患者的就诊日期按时间排序分配序号(date_num: 1,2,3...) mutate(date_num = dense_rank(dx_date)) %>% ungroup() %>% group_by(id, dx_date, date_num) %>% # 为同一就诊日期下的诊断分配序号(code_num:1,2...) mutate(code_num = row_number()) %>% ungroup()
3. 分别宽展日期列和诊断码列
将日期和诊断码分别转换为宽格式,再合并得到目标结构:
# 处理就诊日期列:每个date_num对应一列dx_dateN date_wide <- df_processed %>% distinct(id, date_num, dx_date) %>% pivot_wider( id_cols = id, names_from = date_num, names_prefix = "dx_date", values_from = dx_date ) %>% # 将日期转回原字符串格式 mutate(across(starts_with("dx_date"), ~format(.x, "%m/%d/%y"))) # 处理诊断码列:每个(date_num, code_num)对应一列dx_dateNcodeM code_wide <- df_processed %>% pivot_wider( id_cols = id, names_from = c(date_num, code_num), names_glue = "dx_date{date_num}code{code_num}", values_from = dx_code ) # 合并两个宽表,匹配目标列顺序 df_final <- date_wide %>% left_join(code_wide, by = "id") %>% select( id, dx_date1, dx_date1code1, dx_date1code2, dx_date2, dx_date2code1, dx_date2code2, dx_date3, dx_date3code1 )
4. 查看结果
运行上述代码后,df_final的结构与你想要的df2完全一致:
df_final #> id dx_date1 dx_date1code1 dx_date1code2 dx_date2 dx_date2code1 dx_date2code2 dx_date3 dx_date3code1 #> 1 1 7/11/22 MI HF 8/1/22 PNA <NA> <NA> <NA> #> 2 2 8/4/22 PNA <NA> 8/7/22 Cellulitis <NA> <NA> <NA> #> 3 3 8/4/22 MI <NA> 7/11/22 Flu Sepsis 9/10/22 HF
关键逻辑说明
dense_rank():为每个患者的就诊日期生成连续序号,确保不同日期对应不同的date_numrow_number():为同一日期下的诊断生成序号,区分同一就诊的多个诊断pivot_wider():将长格式数据转换为宽格式,通过names_from和names_glue自定义列名,完美匹配目标格式
内容的提问来源于stack exchange,提问作者Elizabeth Driskill
相关产品推荐
相关产品推荐

