R语言半长型数据转宽型数据 pivot_wider函数使用问题求解
R数据框长转宽实现方案
问题背景
当前需要将按NAME+YEAR存储的长格式成绩表转为宽格式,要求每个NAME仅占一行,不同年份对应的YEAR/MARKS/MAXIMUM字段展开为独立列。之前使用for循环实现性能较差,尝试tidyr::pivot_wider未得到预期结果。
示例原始数据结构如下:
NAME <- c("ABC", "ABC", "ABC", "DEF", "GHI", "GHI", "JKL", "JKL", "JKL", "MNO") YEAR <- c(2012, 2013, 2014, 2012, 2012, 2013, 2012, 2014, 2016, 2013) MARKS <- c(45, 75, 95, 91, 75, 76, 85, 88, 89, 77) MAXIMUM <- c(95, NA, NA, 91, 76, NA, 89, NA, NA, 77) DF <- data.frame( NAME, YEAR, MARKS, MAXIMUM )
原始数据预览:
NAME YEAR MARKS MAXIMUM 1 ABC 2012 45 95 2 ABC 2013 75 NA 3 ABC 2014 95 NA 4 DEF 2012 91 91 5 GHI 2012 75 76 6 GHI 2013 76 NA 7 JKL 2012 85 89 8 JKL 2014 88 NA 9 JKL 2016 89 NA 10 MNO 2013 77 77
实现代码
不需要写for循环,正确配置pivot_wider参数即可高效完成转换,两种常用输出形式的代码如下:
- 按年份顺序序号命名列(适配不同NAME年份数量不一致的场景,不会出现冗余空列)
library(dplyr) library(tidyr) wide_df <- DF %>% group_by(NAME) %>% mutate(seq = row_number()) %>% pivot_wider( id_cols = NAME, names_from = seq, values_from = c(YEAR, MARKS, MAXIMUM), names_sep = "" )
输出列名格式为YEAR1/MARKS1/MAXIMUM1/YEAR2/MARKS2……对应每个NAME下按年份升序排列的第n条记录。
- 按实际年份值命名列
wide_df <- DF %>% pivot_wider( id_cols = NAME, names_from = YEAR, values_from = c(MARKS, MAXIMUM), names_sep = "_" )
输出列名格式为MARKS_2012/MAXIMUM_2012/MARKS_2013……对应各年份的成绩值,无对应年份记录的位置自动填充NA。
两种实现均为向量化运算,数据量较大时性能远高于手写for循环。
内容的提问来源于stack exchange,提问作者Frodo
相关产品推荐
相关产品推荐

