基于聚合值透视列:实现流感疫苗数据单患者一行的宽表转换
患者疫苗接种数据宽表转换解决方案
问题描述
现有患者疫苗接种数据集,包含变量:
ptid:患者IDtime:时间(0=RCT前,1=RCT后)type:流感疫苗类型(有效值为0、1、3,注意原数据中type因子水平为"0"、"1"、"2",实际值需对应转换)num:接种次数(因子型)volume:接种剂量(连续变量)
需将数据转换为每个患者一行的宽表,包含以下衍生变量:
- 剂量汇总变量:
totalvol:患者总接种剂量(不计疫苗类型)voltype0、voltype1、voltype3:按患者+疫苗类型汇总的总剂量
- 接种指示变量:
totalyn:患者是否接种过任意疫苗(是=1,否=0)type0yn、type1yn、type3yn:患者是否接种过对应类型疫苗(是=1,否=0)
原尝试代码存在问题:多次pivot_wider导致生成值列表,且无法重复利用type变量透视,无法得到每行对应单个患者的结果。
解决方案代码
library(dplyr) library(tidyr) # 加载原始数据集 df <- structure(list(ptid = c("30000", "30000", "30000", "30000", "30000", "30001", "30002", "30002", "30002", "30003", "30003", "30003", "30004", "30004", "30004", "30005", "30005", "30005", "30006", "30006", "30006", "30007", "30007", "30007", "30007", "30008", "30008", "30008", "30008", "30008"), num = structure(c(1L, 2L, 3L, 4L, 5L, 1L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 5L), levels = c("1", "2", "3", "4", "5", "6", "7"), class = "factor"), type = structure(c(3L, 3L, 3L, 1L, 1L, 3L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 3L, 1L, 1L, 3L, 3L, 3L, 1L, 1L, 1L, 1L, 1L), levels = c("0", "1", "2"), class = "factor"), time = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 2L, 2L, 1L, 2L, 2L, 2L, 1L, 1L, 2L, 2L, 2L), levels = c("0", "1"), class = "factor"), volume = c(694L, 745L, 415L, 201L, 446L, 589L, 99L, 887L, 266L, 261L, 188L, 391L, 240L, 221L, 578L, 296L, 596L, 204L, 703L, 113L, 370L, 922L, 419L, 168L, 879L, 856L, 800L, 736L, 386L, 912L)), row.names = c(NA, 30L), class = "data.frame") # 核心转换代码 wide_data <- df %>% # 修正疫苗类型值:原因子水平"2"对应业务中的类型3 mutate(type = case_when( type == "0" ~ "0", type == "1" ~ "1", type == "2" ~ "3" )) %>% # 按患者+疫苗类型分组,计算各类型总剂量、标记接种状态 group_by(ptid, type) %>% summarise( vol_type = sum(volume), type_yn = 1, .groups = "drop" ) %>% # 按患者分组,计算总剂量和整体接种状态 group_by(ptid) %>% mutate( totalvol = sum(vol_type), totalyn = 1 ) %>% ungroup() %>% # 一次透视完成宽表转换,未接种类型填充0 pivot_wider( id_cols = ptid, names_from = type, values_from = c(vol_type, type_yn), names_glue = "{.value}{type}", values_fill = list(vol_type = 0, type_yn = 0) ) %>% # 重命名变量匹配需求 rename( voltype0 = vol_type0, voltype1 = vol_type1, voltype3 = vol_type3, type0yn = type_yn0, type1yn = type_yn1, type3yn = type_yn3 ) %>% # 补全总剂量和总接种状态(兼容无接种记录的患者) mutate( totalvol = rowSums(select(., starts_with("voltype"))), totalyn = ifelse(totalvol > 0, 1, 0) ) %>% # 按患者ID排序 arrange(ptid)
代码说明
- 修正类型值:解决原数据中因子水平与实际业务类型不匹配的问题,避免后续命名混乱。
- 分组汇总:先按
ptid+type分组,计算单患者单类型的剂量总和与接种标记,减少后续透视的冗余数据。 - 单次透视成型:用
pivot_wider一次性完成剂量和指示变量的宽表转换,通过names_glue自动生成规范变量名,values_fill对未接种类型填充0,避免NA值。 - 变量补全:通过行求和确保
totalvol的准确性,同时兼容无接种记录的患者场景。
内容的提问来源于stack exchange,提问作者Rstudyer
相关产品推荐
相关产品推荐

