R中如何根据列名末尾.t1/.t3后缀用pivot_longer重构数据框
转换实现方案
该场景为典型的规则化宽格式转长格式任务,无需手动逐一匹配列名,通过正则捕获即可适配所有长度、结构不规则的带固定后缀的列,操作代码可直接复现:
方法1:tidyr 高效实现(推荐)
该方法是R生态中处理宽转长的标准方案,只要列满足.t1/.t3的后缀规则,即使后续新增其他不同长度的带后缀列,代码也无需修改即可自动适配。
首先加载依赖包:
library(tidyr) library(dplyr)
核心逻辑:
- 正则匹配列名时设置两个捕获组:第一组匹配后缀前的任意内容(即需要保留的无前缀列名),第二组匹配
.t后的数字(用于构造Time列) - 借助
pivot_longer的*.value*特殊标记,自动将捕获的前缀内容映射为新数据框的列名,无需手动逐列合并
完整可运行代码:
# 复现输入示例数据 df <- data.frame( "Subject" = c(1:10), "intercept.freq.acc.t1" = c(1:10), "intercept.freq.acc.t3" = c(1:10), "freq.rt.t1" = c(1:10), "freq.rt.t3" = c(1:10), "vowel.con.acc.t1" = c(1:10), "vowel.con.acc.t3" = c(1:10) ) # 执行格式转换 df_long <- df %>% pivot_longer( cols = -Subject, # 固定保留Subject列,其余列全部参与转换 names_to = c(".value", "Time"), # 列名拆分后的映射规则:第一捕获组对应数据列名,第二捕获组对应Time列取值 names_pattern = "(.*)\\.t(\\d)$" # 正则规则:捕获任意前缀 + 固定匹配.t + 捕获末尾的时间数字 ) %>% mutate(Time = paste0("t", Time)) # 把捕获的数字补回t前缀,和示例格式对齐
执行后得到的df_long结构与预期输出完全一致。
方法2:Base R 原生实现(无需加载第三方包)
如果不想依赖tidyverse系列包,可通过基础的字符串匹配、行绑定实现相同效果:
# 匹配所有带.t1/.t3后缀的列名 all_cols <- colnames(df) t1_cols <- grep("\\.t1$", all_cols, value = TRUE) t3_cols <- grep("\\.t3$", all_cols, value = TRUE) # 分别构造t1、t3时间点的数据子集 df_t1 <- cbind( Subject = df$Subject, Time = "t1", setNames(df[t1_cols], gsub("\\.t1$", "", t1_cols)) # 去掉列名末尾的.t1后缀 ) df_t3 <- cbind( Subject = df$Subject, Time = "t3", setNames(df[t3_cols], gsub("\\.t3$", "", t3_cols)) # 去掉列名末尾的.t3后缀 ) # 合并两个子集并调整行顺序,和示例对齐 df_long_base <- rbind(df_t1, df_t3) df_long_base <- df_long_base[order(df_long_base$Subject), ]
内容的提问来源于stack exchange,提问作者Henry Brice
相关产品推荐
相关产品推荐

