You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用R中tidyr的pivot_longer实现嵌套变量的宽转长?

使用pivot_longer()将宽格式数据转换为带嵌套变量的长格式

需求说明

需要将包含多次随访及对应测试结果的宽格式数据,转换为每行对应个体-随访-测试项的长格式数据,最终结构需包含:个体标识(IDno、Sex)、随访次数、随访天数、测试类型、测试结果。

原始宽格式数据

变量说明

  • IDno、Sex:个体基础标识变量
  • fu1、fu2:两次随访的天数
  • cpass1/cpass2、is1/is2:分别对应两次随访的两项测试结果

创建数据代码

IDno <- c(1,2)
Sex <- c("M","F")
fu1 <- c(13,15)
fu2 <- c(20,18)
cpass1 <- c(27, 85)
cpass2 <- c(33, 90)
is1 <- c(201, 400)
is2 <- c(220, 430)
mydata <- data.frame(IDno, Sex, 
                     fu1, cpass1, is1, 
                     fu2, cpass2, is2)

期望的长格式结构

最终数据每行对应一次随访中的一项测试,列名及示例数据如下:

IDnoSexfudaytestvalue
1M113cpass27
1M113is201
1M220cpass33
1M220is220
2F115cpass85
2F115is400
2F218cpass90
2F218is430

尝试的错误代码

以下代码未能得到预期结构,出现了冗余行及列结构混乱:

#重命名变量
mydata_wide <- mydata %>%
  rename(fu1_day = fu1,
         cp_one = cpass1,
         is_one = is1,
         fu2_day = fu2,
         cp_two = cpass2,
         is_two = is2)

#转换格式
mydata_wide %>%
  pivot_longer(
    cols = c(fu1_day, fu2_day),
    names_to = c("fu", ".value"),
    values_to = "day",
    names_sep = "_") %>% 
  pivot_longer(
    cols = c("cp_one", "is_one", "cp_two", "is_two"),
    names_to = c("test", ".value"),
    values_to = "value", 
    names_sep = "_") 

正确解决方案

方法1:直接使用正则匹配变量名

无需提前重命名,通过names_pattern提取变量中的随访次数和类型:

library(tidyverse)

mydata_long <- mydata %>%
  # 第一步:将同随访次数的变量整合,提取随访次数
  pivot_longer(
    cols = -c(IDno, Sex),
    names_to = c(".value", "fu"),
    names_pattern = "(.*)(\\d)"  # 正则匹配:变量名前缀 + 随访数字
  ) %>%
  # 第二步:将测试项转为长格式
  pivot_longer(
    cols = c(cpass, is),
    names_to = "test",
    values_to = "value"
  ) %>%
  # 重命名随访天数列,避免与随访次数列混淆
  rename(day = fu) %>%
  # 调整列顺序至预期结构
  select(IDno, Sex, fu, day, test, value)

print(mydata_long)

方法2:先标准化变量名再转换

先将变量名调整为「类型_随访次数」的格式,再通过names_sep拆分:

library(tidyverse)

# 标准化变量名
mydata_wide <- mydata %>%
  rename(
    fu_day_1 = fu1,
    cpass_1 = cpass1,
    is_1 = is1,
    fu_day_2 = fu2,
    cpass_2 = cpass2,
    is_2 = is2
  )

# 转换格式
mydata_long <- mydata_wide %>%
  pivot_longer(
    cols = -c(IDno, Sex),
    names_to = c("var_type", ".value"),
    names_sep = "_"
  ) %>%
  pivot_longer(
    cols = c(cpass, is),
    names_to = "test",
    values_to = "value"
  ) %>%
  rename(day = fu_day) %>%
  select(IDno, Sex, fu, day, test, value)

print(mydata_long)

两种方法均可得到符合预期的长格式数据。

内容的提问来源于stack exchange,提问作者KIM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 16:16:13