R语言如何将同一ID的多行重复测量数据转为单行宽格式数据
R语言长格式数据转宽格式(按参与者拆分时间点列)实操方案
核心思路
你要做的是标准的长格式转宽格式操作:把“每一行代表一次独立观测”的长表,转为“每一行对应一个参与者、不同时间点的测量结果单独成列”的宽表。R有成熟的内置/第三方函数可以直接实现,完全不需要写循环、手动拆分子集再merge,还能天然适配你遇到的两个痛点:
- 不同参与者测量次数差异大:函数会自动按全数据集的最大测量次数生成对应列,测量次数不足的参与者对应单元格自动填充NA,不会触发报错
- 存在缺失值:缺失的观测会被自动识别处理,不会出现列名冲突、匹配错位的问题
方法1:tidyr包pivot_wider(最推荐)
这是目前tidyverse生态下最简洁、维护最好的实现,代码可读性高,没有副作用。
# 首次使用先安装:install.packages("tidyr") library(tidyr) # 核心转换代码 B1 <- A1 %>% pivot_wider( id_cols = id, # 以id为聚合唯一行的依据 names_from = time, # 新列名来自time的测量编号 names_prefix = "x", # 给新列加x前缀,自动生成x1/x2/x3...的格式 values_from = x # 新列的填充值来自结果变量x )
不管数据集里最多有多少个时间点(哪怕最多10次测量),函数都会自动生成对应数量的列;某个参与者没有对应次数的测量时,单元格自动补NA,完全不需要手动处理特殊场景。
方法2:reshape2包dcast(经典实现)
如果习惯用经典的reshape2包,可以用dcast快速实现:
# 首次使用先安装:install.packages("reshape2") library(reshape2) B1 <- dcast( data = A1, formula = id ~ time, # 行维度按id拆分,列维度按time拆分 value.var = "x" ) # 给列加x前缀,匹配要求的x1/x2命名格式 colnames(B1)[-1] <- paste0("x", colnames(B1)[-1])
方法3:基础R内置reshape(无需额外安装包)
如果不想安装第三方包,可以直接用R自带的reshape函数实现:
B1 <- reshape( data = A1, idvar = "id", # 唯一行的标识列是id timevar = "time", # 用来拆分列的变量是time direction = "wide", # 指定转换方向为宽格式(长转宽) v.names = "x" # 要拆分的结果变量是x ) # 把默认生成的x.1/x.2格式列名,替换成要求的x1/x2格式 colnames(B1) <- gsub("x\\.", "x", colnames(B1))
原尝试方案的问题
- 手写循环+
eval(parse)的方式:动态拼接代码执行的逻辑效率低、冗余度高,当某个参与者没有对应时间点的测量时,赋值操作会因为找不到匹配位置直接报错,调试成本极高。 - 手动拆分数据集再merge的方式:默认merge是内连接,会直接删除没有完成全部测量的参与者;同时每次合并后time、x列会因为重名被自动重命名为
time.x/time.y、x.x/x.y,不手动批量修正列名就会出现识别错误。
内容的提问来源于stack exchange,提问作者Eric Boorman
相关产品推荐
相关产品推荐

