如何用dplyr的pivot_wider同时完成两类不同规则的宽表转换?
用dplyr实现不同规则的宽表转换
问题背景
需要将整洁数据集转换为宽格式,两类列需遵循不同的转换规则:
score列:按measure和day组合生成对应的宽表列tot列:仅按measure生成对应的宽表列(tot是id+measure分组下score的总和,同一分组内值恒定)
但直接执行以下代码时,tot列会被错误地按measure+day生成重复列:
df %>% pivot_wider(names_from = c(measure, day), values_from = c(score, tot))
示例数据集
生成示例数据的代码:
library(dplyr) df <- data.frame(id = rep(c("DFE3", "DFE76"), each = 12), measure = rep(letters[1:3], each = 4, length.out = 24), day = rep(1:4, times = 3, length.out = 24), score = sample(0:5, 24, replace = T)) %>% arrange(id, measure, day) %>% group_by(id, measure) %>% mutate(tot = sum(score)) %>% ungroup
数据集结构:
# # A tibble: 24 x 5 # id measure day score tot # <fct> <fct> <int> <int> <int> # 1 DFE3 a 1 5 12 # 2 DFE3 a 2 2 12 # ...(省略其余行)
解决方案
由于score和tot的转换维度不同,无法通过单次pivot_wider直接实现,推荐以下两种方法:
方法1:拆分转换后合并
分别处理两类列生成宽表,再通过id合并:
# 生成score的宽表:按measure+day命名 score_wide <- df %>% pivot_wider( id_cols = id, names_from = c(measure, day), values_from = score, names_prefix = "score_" ) # 生成tot的宽表:先去重(同一id+measure下tot值唯一),再按measure命名 tot_wide <- df %>% select(id, measure, tot) %>% distinct() %>% pivot_wider( id_cols = id, names_from = measure, values_from = tot, names_prefix = "tot_" ) # 合并得到最终宽表 final_wide <- score_wide %>% left_join(tot_wide, by = "id")
方法2:单次pivot结合去重函数
在处理tot列时,利用values_fn参数取分组内的唯一值,避免重复列:
final_wide <- df %>% # 先处理score的宽表转换 pivot_wider( id_cols = id, names_from = c(measure, day), values_from = score, names_prefix = "score_" ) %>% # 左连接处理后的tot宽表 left_join( df %>% pivot_wider( id_cols = id, names_from = measure, values_from = tot, values_fn = first, # 取分组内第一个值(因tot值恒定) names_prefix = "tot_" ), by = "id" )
最终生成的宽表会包含类似score_a_1、score_b_3的分数列,以及tot_a、tot_c的总和列,完全符合需求。
内容的提问来源于stack exchange,提问作者llewmills
相关产品推荐
相关产品推荐

