如何用tidyverse::spread将长格式DataFrame转为宽格式并包含所有变量?
搞定多变量长格式转宽格式的tidyverse方案
嘿,我来帮你解决这个问题!你想要把长格式的df按respid分组,把每个member_id对应的gender、edu、dob都转成带序号的宽格式列对吧?你的尝试只处理了单个变量,而且分组逻辑有点小问题,下面给你两种靠谱的解决办法:
先修正你的输入数据(小细节)
首先你的原始df代码格式有点小问题,我先帮你调整成可直接运行的版本:
library(tidyverse) df <- tibble::tribble( ~respid, ~member_id, ~gender, ~edu, ~dob, 100L, 1L, 1L, 3L, 1978L, 100L, 2L, 1L, 3L, 1980L, 200L, 1L, 1L, 4L, 1974L, 200L, 2L, 2L, 5L, 1955L, 300L, 1L, 2L, 3L, 1998L, 300L, 2L, 1L, 4L, 1999L, 300L, 3L, 2L, 3L, 2001L )
方案1:用spread(兼容旧版tidyverse)
spread一次只能处理一个值列,所以我们得先把多个变量收拢成键值对,再展开:
output_spread <- df %>% # 先把gender/edu/dob这三个变量收拢成统一的键(var)和值(val)列 gather(key = "var", value = "val", gender, edu, dob) %>% # 生成带成员序号的新列名,比如gender_1、edu_2 mutate(var_member = paste0(var, "_", member_id)) %>% # 去掉不需要的中间列 select(-var, -member_id) %>% # 转成宽格式 spread(key = var_member, value = val) %>% # 按respid排序,和你期望的输出一致 arrange(respid)
方案2:用pivot_wider(tidyverse推荐的新版函数,更简洁)
现在tidyverse更推荐用pivot_wider,它直接支持多变量转宽,还能自定义列名格式,代码清爽很多:
output_pivot <- df %>% pivot_wider( id_cols = respid, # 按respid作为分组主键 names_from = member_id, # 用member_id作为列名的后缀 values_from = c(gender, edu, dob), # 需要转宽的所有变量 names_glue = "{.value}_{names_from}" # 定义列名格式:变量名_成员ID ) %>% arrange(respid)
为什么你之前的代码不对?
- 你错误地按
member_id分组了!应该按respid分组——member_id是每个respid下的成员序号,只有按respid分组,才能正确对应每个成员的位置; - 你只处理了
gender一个变量,没对edu和dob做同样操作,所以没法得到完整的宽格式数据。
运行上面任意一种方案,都能得到你想要的output结果,pivot_wider是现在更推荐的写法哦~
内容的提问来源于stack exchange,提问作者Ann
相关产品推荐
相关产品推荐

