如何在R中使用pivot_longer处理多列实现宽表转长表?
解决方案
首先修正原始数据中的笔误(di2_event_time应为dis2_event_time,否则无法正确匹配分组),然后使用pivot_longer的多列匹配功能一次性完成转换:
library(tidyverse) # 修正列名后的原始数据 df = tribble( ~id, ~dis1_event, ~dis1_event_time, ~dis2_event, ~dis2_event_time, 1, 1, '2022-01-01', 0, '2022-12-31', 2, 0, '2018-01-01', 1, '2018-03-01', ) # 宽转长的正确代码 df_result <- df %>% pivot_longer( cols = -id, # 保留id列,转换其余所有列 names_to = c("disease", ".value"), # 拆分列名为两个部分:疾病标识,以及值对应的字段名 names_pattern = "(dis\\d)_(.*)" # 正则表达式捕获分组:第一组匹配dis1/dis2,第二组匹配event/event_time ) %>% rename(time = event_time) # 将event_time重命名为time,匹配期望格式 # 验证结果与预期一致 all.equal(df_result, df_expected) # [1] TRUE
关键逻辑说明
names_to = c("disease", ".value"):names_to参数支持拆分列名为多个部分,其中.value是pivot_longer的特殊关键字,表示将第二部分捕获的内容作为新列名,同时把对应列的值填充到该列下。这能让dis1_event和dis1_event_time的值分别对应到event和event_time列,且归属同一个disease = "dis1"的分组。names_pattern正则匹配:(dis\\d)匹配dis1/dis2作为疾病标识,(.*)匹配后续的event或event_time作为字段类型,确保同一疾病的两列被分到同一组,不会出现错位。- 重命名列:最后通过
rename()把event_time改成time,和期望输出的列名完全一致。
为什么你的尝试失败?
连续两次调用pivot_longer会导致数据膨胀:第一次转换event列后,每个id生成2行数据;第二次转换time列时,每一行又会被拆成2行,最终得到8行数据,且disease列会出现重复和不匹配的情况,无法对应到正确的疾病-事件-时间组合。
内容的提问来源于stack exchange,提问作者zhiwei li
相关产品推荐
相关产品推荐

