R语言宽表转长表(含Stub变量):无需指定全部Stub实现转换
无需手动指定全部Stub,将带重复测量的宽格式数据转为长格式
问题背景
现有宽格式数据HAVE,变量名由时间标识前缀(如T/P)+时间数字+科目名称组成,需要转换为包含TIME列和各科目列的长格式数据WANT,且无需手动指定所有科目Stub。
原始与目标数据
宽格式输入(HAVE)
HAVE = data.frame(STUDENT=c(1,2), CLASS = c(100,200), T1CHE=c(95,NA), T2CHE=c(13,66), T3CHE=c(99,1), T1CHES=c(81,NA), T2CHES=c(43,59), T3CHES=c(3,25), P11MATH=c(56,88), P12MATH=c(33,40), P5MATHS=c(100,31), P6MATHS=c(88,36), T2ENG=c(37,63), T3ENG=c(46,38), T4ENG=c(14,74))
长格式目标(WANT)
WANT = data.frame(STUDENT=c(1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2), CLASS = c(100,100,100,100,100,100,100,100,200,200,200,200,200,200,200,200), TIME=c(1,2,3,4,5,6,11,12,1,2,3,4,5,6,11,12), CHE=c(95,13,99,NA,NA,NA,NA,NA,NA,66,1,NA,NA,NA,NA,NA), CHES=c(81,43,3,NA,NA,NA,NA,NA,NA,59,25,NA,NA,NA,NA,NA), MATH=c(NA,NA,NA,NA,NA,NA,56,33,NA,NA,NA,NA,NA,NA,88,40), MATHS=c(NA,NA,NA,NA,100,88,NA,NA,NA,NA,NA,NA,31,36,NA,NA), ENG=c(NA,37,46,14,NA,NA,NA,NA,NA,63,38,74,NA,NA,NA,NA))
解决方案
使用tidyr的pivot_longer+pivot_wider组合,结合正则表达式自动拆分变量名中的时间和科目信息,无需手动枚举所有Stub:
library(tidyr) library(dplyr) # 转换数据 result <- HAVE %>% # 第一步:将测量变量转成长格式,提取时间标识和科目 pivot_longer( cols = -c(STUDENT, CLASS), names_to = c("prefix", "TIME", "SUBJECT"), names_pattern = "^([A-Z])(\\d+)([A-Z]+)$", values_to = "score" ) %>% # 第二步:将科目转成列,对应各科目得分 pivot_wider(names_from = SUBJECT, values_from = score) %>% # 移除无用的prefix列,转换TIME为数值型 select(-prefix) %>% mutate(TIME = as.integer(TIME)) %>% # 补充所有需要的TIME值,填充缺失的得分 complete(STUDENT, CLASS, TIME = c(1,2,3,4,5,6,11,12)) %>% # 按学生和时间排序,匹配目标数据顺序 arrange(STUDENT, TIME) # 验证结果是否与WANT一致 all.equal(result, WANT)
关键细节说明
- 正则表达式:
^([A-Z])(\\d+)([A-Z]+)$精准拆分变量名:([A-Z]):匹配开头的T/P前缀(\\d+):匹配时间数字(如1、11)([A-Z]+):匹配科目名称(如CHE、MATH)
- complete函数:确保所有指定的TIME值(1,2,3,4,5,6,11,12)都存在,缺失的得分自动填充为NA
- 排序:
arrange(STUDENT, TIME)保证结果顺序与WANT完全一致
运行代码后,result会和WANT完全匹配,all.equal(result, WANT)会返回TRUE。
内容的提问来源于stack exchange,提问作者bvowe
相关产品推荐
相关产品推荐

